From 2d2efc070a6239a76e80e2d452f1f4fad4b20985 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 12 May 2015 17:52:03 +0200 Subject: [PATCH 01/70] Gas estimation --- mix/CodeModel.cpp | 49 +++++++++++++++++++++++++++++++++++ mix/CodeModel.h | 25 ++++++++++++++++++ mix/qml/CodeEditorView.qml | 4 +++ mix/qml/WebCodeEditor.qml | 8 ++++++ mix/qml/html/cm/solarized.css | 4 +++ mix/qml/html/codeeditor.js | 23 +++++++++++++++- 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 636a665e6..ecdb46be3 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include "QContractDefinition.h" @@ -41,6 +43,7 @@ #include "CodeHighlighter.h" #include "FileIo.h" #include "CodeModel.h" +#include "QBigInt.h" using namespace dev::mix; @@ -50,6 +53,7 @@ const std::set c_predefinedContracts = namespace { +using namespace dev::eth; using namespace dev::solidity; class CollectLocalsVisitor: public ASTConstVisitor @@ -185,6 +189,7 @@ CodeModel::CodeModel(): qRegisterMetaType("QContractDefinition*"); qRegisterMetaType("QFunctionDefinition*"); qRegisterMetaType("QVariableDeclaration*"); + //qRegisterMetaType("GasMap"); qmlRegisterType("org.ethereum.qml", 1, 0, "QFunctionDefinition"); qmlRegisterType("org.ethereum.qml", 1, 0, "QVariableDeclaration"); } @@ -292,6 +297,7 @@ void CodeModel::runCompilationJob(int _jobId) } } cs.compile(false); + gasEstimation(cs); collectContracts(cs, sourceNames); } catch (dev::Exception const& _exception) @@ -314,6 +320,49 @@ void CodeModel::runCompilationJob(int _jobId) emit stateChanged(); } +void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) +{ + m_gasCostsMaps.clear(); + for (std::string n: _cs.getContractNames()) + { + + ContractDefinition const& contractDefinition = _cs.getContractDefinition(n); + QString sourceName = QString::fromStdString(*contractDefinition.getLocation().sourceName); + + if (!m_gasCostsMaps.contains(sourceName)) + m_gasCostsMaps.insert(sourceName, QVariantList()); + + if (!contractDefinition.isFullyImplemented()) + continue; + dev::solidity::SourceUnit const& sourceUnit = _cs.getAST(*contractDefinition.getLocation().sourceName); + AssemblyItems const* items = _cs.getRuntimeAssemblyItems(n); + + StructuralGasEstimator estimator; + std::map gasCosts = estimator.breakToStatementLevel(estimator.performEstimation(*items, std::vector({&sourceUnit})), {&sourceUnit}); + + for (auto gasIte = gasCosts.begin(); gasIte != gasCosts.end(); ++gasIte) + { + SourceLocation location = gasIte->first->getLocation(); + GasMeter::GasConsumption cost = gasIte->second; + GasMap* gas = new GasMap(location.start, location.end, (new QBigInt(cost.value))->value()); + m_gasCostsMaps.find(sourceName).value().push_back(QVariant::fromValue(gas)); + } + } +} + +QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const +{ + if (m_gasCostsMaps.contains(_documentId)) + { + auto sourceMapIter = m_gasCostsMaps.find(_documentId); + int gg = sourceMapIter.value().size(); + Q_UNUSED(gg); + return sourceMapIter.value(); + } + else + return QVariantList(); +} + void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames) { Guard pl(x_pendingContracts); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 3f713a17b..a1a2c29ec 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -32,6 +32,7 @@ #include #include #include "SolidityType.h" +#include "QBigInt.h" class QTextDocument; @@ -126,7 +127,24 @@ struct SourceMap LocationMap functions; }; +class GasMap: public QObject +{ + Q_OBJECT + + Q_PROPERTY(int start MEMBER m_start CONSTANT) + Q_PROPERTY(int end MEMBER m_end CONSTANT) + Q_PROPERTY(QString gas MEMBER m_gas CONSTANT) + +public: + GasMap(int _start, int _end, QString _gas): m_start(_start), m_end(_end), m_gas(_gas) {} + + int m_start; + int m_end; + QString m_gas; +}; + using SourceMaps = QMap; //by source id +using GasCostsMaps = QMap*/>; //gas cost by contract name /// Code compilation model. Compiles contracts in background an provides compiled contract data class CodeModel: public QObject @@ -166,6 +184,10 @@ public: bool isContractOrFunctionLocation(dev::SourceLocation const& _location); /// Get funciton name by location QString resolveFunctionName(dev::SourceLocation const& _location); + /// Gas estimation for compiled sources + void gasEstimation(solidity::CompilerStack const& _cs); + /// Gas cost by doc id + Q_INVOKABLE QVariantList gasCostByDocumentId(QString const& _documentId) const; signals: /// Emited on compilation state change @@ -201,6 +223,7 @@ private: mutable dev::Mutex x_contractMap; ContractMap m_contractMap; SourceMaps m_sourceMaps; + GasCostsMaps m_gasCostsMaps; std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; @@ -214,3 +237,5 @@ private: } } + +//Q_DECLARE_METATYPE(dev::mix::GasMap) diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index e4d62ed81..08bb072f5 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -177,6 +177,10 @@ Item { } onCompilationComplete: { sourceInError = ""; + var gasCosts = codeModel.gasCostByDocumentId(currentDocumentId); + var editor = getEditor(currentDocumentId); + if (editor) + editor.displayGasCosts(gasCosts); } } diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index 38f2327b1..a2602304a 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -83,6 +83,14 @@ Item { editorBrowser.runJavaScript("setFontSize(" + size + ")", function(result) {}); } + function displayGasCosts(gasCosts) { + + //console.log(gasCosts); + //console.log(JSON.stringify(gasCosts)); + if (initialized && editorBrowser) + editorBrowser.runJavaScript("displayGasCosts('" + JSON.stringify(gasCosts) + "')", function(result) {}); + } + Clipboard { id: clipboard diff --git a/mix/qml/html/cm/solarized.css b/mix/qml/html/cm/solarized.css index b8cede806..046042450 100644 --- a/mix/qml/html/cm/solarized.css +++ b/mix/qml/html/cm/solarized.css @@ -189,3 +189,7 @@ view-port } span.CodeMirror-selectedtext { color: #586e75 !important; } + +.gasCost { + background: #b58900 !important; +} diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index d25fbd091..cc5e9a28c 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -3,7 +3,7 @@ var editor = CodeMirror(document.body, { //styleActiveLine: true, matchBrackets: true, autofocus: true, - gutters: ["CodeMirror-linenumbers", "breakpoints"], + gutters: ["CodeMirror-linenumbers", "breakpoints", "gasCost"], autoCloseBrackets: true, styleSelectedText: true }); @@ -203,5 +203,26 @@ setFontSize = function(size) editor.refresh(); } +makeGasCostMarker = function(value) { + var marker = document.createElement("div"); + marker.style.color = "#822"; + marker.innerHTML = value; + return marker; +}; + +displayGasCosts = function(gasCosts) +{ + gasCosts = JSON.parse(gasCosts); + for (var i in gasCosts) + { + var line = editor.posFromIndex(gasCosts[i].start); + console.log("___________") + console.log(line.line); + console.log(gasCosts[i].start); + //editor.setGutterMarker(line.line, "gasCost", makeGasCostMarker(gasCosts[i].gas)); + editor.markText(editor.posFromIndex(gasCosts[i].start), editor.posFromIndex(gasCosts[i].end), { className: "gasCost" }); + } +} + editor.setOption("extraKeys", extraKeys); From 3881b160d64938d840c9a3cdcbba31aee9f15985 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 15 May 2015 11:26:19 +0200 Subject: [PATCH 02/70] Display gas estimation as annotation --- mix/CodeModel.cpp | 8 ++-- mix/CodeModel.h | 6 ++- mix/qml/Application.qml | 15 ++++++ mix/qml/CodeEditorView.qml | 9 +++- mix/qml/WebCodeEditor.qml | 10 ++-- mix/qml/html/cm/solarized.css | 6 ++- mix/qml/html/codeeditor.js | 87 +++++++++++++++++++++++++++++++---- 7 files changed, 117 insertions(+), 24 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index ecdb46be3..d9262586b 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -189,7 +189,6 @@ CodeModel::CodeModel(): qRegisterMetaType("QContractDefinition*"); qRegisterMetaType("QFunctionDefinition*"); qRegisterMetaType("QVariableDeclaration*"); - //qRegisterMetaType("GasMap"); qmlRegisterType("org.ethereum.qml", 1, 0, "QFunctionDefinition"); qmlRegisterType("org.ethereum.qml", 1, 0, "QVariableDeclaration"); } @@ -325,7 +324,6 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) m_gasCostsMaps.clear(); for (std::string n: _cs.getContractNames()) { - ContractDefinition const& contractDefinition = _cs.getContractDefinition(n); QString sourceName = QString::fromStdString(*contractDefinition.getLocation().sourceName); @@ -344,7 +342,9 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) { SourceLocation location = gasIte->first->getLocation(); GasMeter::GasConsumption cost = gasIte->second; - GasMap* gas = new GasMap(location.start, location.end, (new QBigInt(cost.value))->value()); + std::stringstream v; + v << cost.value; + GasMap* gas = new GasMap(location.start, location.end, QString::fromStdString(v.str()), gasIte->second.isInfinite); m_gasCostsMaps.find(sourceName).value().push_back(QVariant::fromValue(gas)); } } @@ -355,8 +355,6 @@ QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const if (m_gasCostsMaps.contains(_documentId)) { auto sourceMapIter = m_gasCostsMaps.find(_documentId); - int gg = sourceMapIter.value().size(); - Q_UNUSED(gg); return sourceMapIter.value(); } else diff --git a/mix/CodeModel.h b/mix/CodeModel.h index a1a2c29ec..b28c5f6c6 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -134,17 +134,19 @@ class GasMap: public QObject Q_PROPERTY(int start MEMBER m_start CONSTANT) Q_PROPERTY(int end MEMBER m_end CONSTANT) Q_PROPERTY(QString gas MEMBER m_gas CONSTANT) + Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) public: - GasMap(int _start, int _end, QString _gas): m_start(_start), m_end(_end), m_gas(_gas) {} + GasMap(int _start, int _end, QString _gas, bool _isInfinite): m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) {} int m_start; int m_end; QString m_gas; + bool m_isInfinite; }; using SourceMaps = QMap; //by source id -using GasCostsMaps = QMap*/>; //gas cost by contract name +using GasCostsMaps = QMap; //gas cost by contract name /// Code compilation model. Compiles contracts in background an provides compiled contract data class CodeModel: public QObject diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index fe62efe12..161f7141a 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -116,6 +116,10 @@ ApplicationWindow { MenuSeparator {} MenuItem { action: toggleAssemblyDebuggingAction } } + Menu { + title: qsTr("Tools") + MenuItem { action: gasEstimationAction } + } Menu { title: qsTr("Windows") MenuItem { action: openNextDocumentAction } @@ -409,4 +413,15 @@ ApplicationWindow { mainContent.codeEditor.goToCompilationError(); } } + + Action { + id: gasEstimationAction + text: qsTr("Display gas estimation") + shortcut: "Ctrl+G" + checkable: true + onTriggered: + { + mainContent.codeEditor.displayGasEstimation(checked); + } + } } diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 08bb072f5..08610a8e1 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -168,6 +168,13 @@ Item { editors.itemAt(i).item.setFontSize(size); } + function displayGasEstimation(checked) + { + var editor = getEditor(currentDocumentId); + if (editor) + editor.displayGasEstimation(checked); + } + Component.onCompleted: projectModel.codeEditor = codeEditorView; Connections { @@ -180,7 +187,7 @@ Item { var gasCosts = codeModel.gasCostByDocumentId(currentDocumentId); var editor = getEditor(currentDocumentId); if (editor) - editor.displayGasCosts(gasCosts); + editor.setGasCosts(gasCosts); } } diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index a2602304a..0d681d79c 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -83,12 +83,14 @@ Item { editorBrowser.runJavaScript("setFontSize(" + size + ")", function(result) {}); } - function displayGasCosts(gasCosts) { + function setGasCosts(gasCosts) { + if (initialized && editorBrowser) + editorBrowser.runJavaScript("setGasCosts('" + JSON.stringify(gasCosts) + "')", function(result) {}); + } - //console.log(gasCosts); - //console.log(JSON.stringify(gasCosts)); + function displayGasEstimation(show) { if (initialized && editorBrowser) - editorBrowser.runJavaScript("displayGasCosts('" + JSON.stringify(gasCosts) + "')", function(result) {}); + editorBrowser.runJavaScript("displayGasEstimation('" + show + "')", function(result) {}); } Clipboard diff --git a/mix/qml/html/cm/solarized.css b/mix/qml/html/cm/solarized.css index 046042450..1d298b990 100644 --- a/mix/qml/html/cm/solarized.css +++ b/mix/qml/html/cm/solarized.css @@ -190,6 +190,8 @@ view-port span.CodeMirror-selectedtext { color: #586e75 !important; } -.gasCost { - background: #b58900 !important; +/* Gas Costs */ +.CodeMirror-gasCosts { + border-bottom: double 1px #2aa198; } + diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index cc5e9a28c..3e1a54958 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -3,7 +3,7 @@ var editor = CodeMirror(document.body, { //styleActiveLine: true, matchBrackets: true, autofocus: true, - gutters: ["CodeMirror-linenumbers", "breakpoints", "gasCost"], + gutters: ["CodeMirror-linenumbers", "breakpoints"], autoCloseBrackets: true, styleSelectedText: true }); @@ -207,22 +207,89 @@ makeGasCostMarker = function(value) { var marker = document.createElement("div"); marker.style.color = "#822"; marker.innerHTML = value; + marker.className = "CodeMirror-errorannotation-context"; return marker; }; -displayGasCosts = function(gasCosts) +var gasCosts = null; +setGasCosts = function(_gasCosts) { - gasCosts = JSON.parse(gasCosts); - for (var i in gasCosts) + gasCosts = JSON.parse(_gasCosts); + + if (showGasEstimation) + { + displayGasEstimation(false); + displayGasEstimation(true); + } +} + +var showGasEstimation = false; +var gasMarkText = []; +var gasMarkRef = {}; +displayGasEstimation = function(show) +{ + show = JSON.parse(show); + showGasEstimation = show; + if (show) + { + var maxGas = 20000; + var step = colorGradient.length / maxGas; // 20000 max gas + gasMarkRef = []; + gasMarkRef = {}; + for (var i in gasCosts) + { + if (gasCosts[i].gas !== "0") + { + var color; + var colorIndex = Math.round(step * gasCosts[i].gas); + if (gasCosts[i].isInfinite || colorIndex > colorGradient.length) + color = colorGradient[colorGradient.length - 1]; + else + color = colorGradient[colorIndex]; + var className = "CodeMirror-gasCosts" + i; + var line = editor.posFromIndex(gasCosts[i].start) + gasMarkText.push(editor.markText(line, editor.posFromIndex(gasCosts[i].end), { inclusiveLeft: true, inclusiveRight: true, handleMouseEvents: true, className: className, css: "background-color:" + color })); + gasMarkRef[className] = { line: line.line, value: gasCosts[i] }; + } + } + CodeMirror.on(editor.getWrapperElement(), "mouseover", listenMouseOver); + } + else { - var line = editor.posFromIndex(gasCosts[i].start); - console.log("___________") - console.log(line.line); - console.log(gasCosts[i].start); - //editor.setGutterMarker(line.line, "gasCost", makeGasCostMarker(gasCosts[i].gas)); - editor.markText(editor.posFromIndex(gasCosts[i].start), editor.posFromIndex(gasCosts[i].end), { className: "gasCost" }); + CodeMirror.off(editor.getWrapperElement(), "mouseover", listenMouseOver); + for (var k in gasMarkText) + gasMarkText[k].clear(); + if (gasAnnotation) + { + gasAnnotation.clear(); + gasAnnotation = null; + } + } +} + +var gasAnnotation; +function listenMouseOver(e) +{ + var node = e.target || e.srcElement; + if (node) { + if (!gasAnnotation && node.className && node.className.indexOf("CodeMirror-gasCosts") !== -1) + { + if (gasAnnotation) + gasAnnotation.clear(); + var cl = node.className.split(" ")[1]; + var gasTitle = gasMarkRef[cl].value.isInfinite ? "infinite" : gasMarkRef[cl].value.gas; + gasTitle = gasTitle + " gas"; + gasAnnotation = editor.addLineWidget(gasMarkRef[cl].line + 1, makeGasCostMarker(gasTitle), { coverGutter: false, above: true }); + } + else if (gasAnnotation) + { + gasAnnotation.clear(); + gasAnnotation = null; + } } } +// blue => red ["#1515ED", "#1714EA", "#1914E8", "#1B14E6", "#1D14E4", "#1F14E2", "#2214E0", "#2414DE", "#2614DC", "#2813DA", "#2A13D8", "#2D13D6", "#2F13D4", "#3113D2", "#3313D0", "#3513CE", "#3713CC", "#3A12CA", "#3C12C8", "#3E12C6", "#4012C4", "#4212C2", "#4512C0", "#4712BE", "#4912BC", "#4B11BA", "#4D11B8", "#4F11B6", "#5211B4", "#5411B2", "#5611B0", "#5811AE", "#5A11AC", "#5D11AA", "#5F10A7", "#6110A5", "#6310A3", "#6510A1", "#67109F", "#6A109D", "#6C109B", "#6E1099", "#700F97", "#720F95", "#750F93", "#770F91", "#790F8F", "#7B0F8D", "#7D0F8B", "#7F0F89", "#820E87", "#840E85", "#860E83", "#880E81", "#8A0E7F", "#8D0E7D", "#8F0E7B", "#910E79", "#930D77", "#950D75", "#970D73", "#9A0D71", "#9C0D6F", "#9E0D6D", "#A00D6B", "#A20D69", "#A50D67", "#A70C64", "#A90C62", "#AB0C60", "#AD0C5E", "#AF0C5C", "#B20C5A", "#B40C58", "#B60C56", "#B80B54", "#BA0B52", "#BD0B50", "#BF0B4E", "#C10B4C", "#C30B4A", "#C50B48", "#C70B46", "#CA0A44", "#CC0A42", "#CE0A40", "#D00A3E", "#D20A3C", "#D50A3A", "#D70A38", "#D90A36", "#DB0934", "#DD0932", "#DF0930", "#E2092E", "#E4092C", "#E6092A", "#E80928", "#EA0926", "#ED0924"] +/* green => red */ var colorGradient = ["#429C27", "#439A26", "#449926", "#469726", "#479626", "#489525", "#4A9325", "#4B9225", "#4D9025", "#4E8F25", "#4F8E24", "#518C24", "#528B24", "#548924", "#558824", "#568723", "#588523", "#598423", "#5B8223", "#5C8122", "#5D8022", "#5F7E22", "#607D22", "#627B22", "#637A21", "#647921", "#667721", "#677621", "#697421", "#6A7320", "#6B7220", "#6D7020", "#6E6F20", "#706E20", "#716C1F", "#726B1F", "#74691F", "#75681F", "#76671E", "#78651E", "#79641E", "#7B621E", "#7C611E", "#7D601D", "#7F5E1D", "#805D1D", "#825B1D", "#835A1D", "#84591C", "#86571C", "#87561C", "#89541C", "#8A531B", "#8B521B", "#8D501B", "#8E4F1B", "#904D1B", "#914C1A", "#924B1A", "#94491A", "#95481A", "#97461A", "#984519", "#994419", "#9B4219", "#9C4119", "#9E4019", "#9F3E18", "#A03D18", "#A23B18", "#A33A18", "#A43917", "#A63717", "#A73617", "#A93417", "#AA3317", "#AB3216", "#AD3016", "#AE2F16", "#B02D16", "#B12C16", "#B22B15", "#B42915", "#B52815", "#B72615", "#B82514", "#B92414", "#BB2214", "#BC2114", "#BE1F14", "#BF1E13", "#C01D13", "#C21B13", "#C31A13", "#C51813", "#C61712", "#C71612", "#C91412", "#CA1312", "#CC1212"] editor.setOption("extraKeys", extraKeys); From dc054d7b53ef74274216257d86cd68e33d906cdf Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 15 May 2015 12:01:20 +0200 Subject: [PATCH 03/70] bug fix --- mix/CodeModel.cpp | 1 - mix/qml/CodeEditorView.qml | 1 + mix/qml/WebCodeEditor.qml | 5 +++++ mix/qml/html/codeeditor.js | 19 +++++++++++++------ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index d9262586b..71a2f0eba 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -43,7 +43,6 @@ #include "CodeHighlighter.h" #include "FileIo.h" #include "CodeModel.h" -#include "QBigInt.h" using namespace dev::mix; diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 08610a8e1..a5f8cd233 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -288,6 +288,7 @@ Item { messageDialog.doc = editorListModel.get(index); messageDialog.open(); } + loader.item.displayGasEstimation(gasEstimationAction.checked); } } Component.onCompleted: { diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index 0d681d79c..562c9716b 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -144,7 +144,12 @@ Item { function compilationComplete() { if (editorBrowser) + { editorBrowser.runJavaScript("compilationComplete()", function(result) { }); + parent.displayGasEstimation(gasEstimationAction.checked); + } + + } function compilationError(error, sourceName) diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 3e1a54958..7d68f4032 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -216,25 +216,26 @@ setGasCosts = function(_gasCosts) { gasCosts = JSON.parse(_gasCosts); - if (showGasEstimation) + if (showingGasEstimation) { displayGasEstimation(false); displayGasEstimation(true); } } -var showGasEstimation = false; +var showingGasEstimation = false; var gasMarkText = []; var gasMarkRef = {}; displayGasEstimation = function(show) { show = JSON.parse(show); - showGasEstimation = show; + showingGasEstimation = show; if (show) { var maxGas = 20000; var step = colorGradient.length / maxGas; // 20000 max gas - gasMarkRef = []; + clearGasMark(); + gasMarkText = []; gasMarkRef = {}; for (var i in gasCosts) { @@ -257,8 +258,7 @@ displayGasEstimation = function(show) else { CodeMirror.off(editor.getWrapperElement(), "mouseover", listenMouseOver); - for (var k in gasMarkText) - gasMarkText[k].clear(); + clearGasMark(); if (gasAnnotation) { gasAnnotation.clear(); @@ -267,6 +267,13 @@ displayGasEstimation = function(show) } } +function clearGasMark() +{ + if (gasMarkText) + for (var k in gasMarkText) + gasMarkText[k].clear(); +} + var gasAnnotation; function listenMouseOver(e) { From 177e99c29b62e7765b7c3dacaa7d556b8af4aa04 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 15 May 2015 15:12:34 +0200 Subject: [PATCH 04/70] bug fix --- mix/CodeModel.cpp | 5 +++-- mix/CodeModel.h | 2 +- mix/qml/html/codeeditor.js | 20 ++++++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 15d5a7679..7a0325b7a 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -352,7 +352,7 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) for (auto gasIte = gasCosts.begin(); gasIte != gasCosts.end(); ++gasIte) { - SourceLocation location = gasIte->first->getLocation(); + SourceLocation const& location = gasIte->first->getLocation(); GasMeter::GasConsumption cost = gasIte->second; std::stringstream v; v << cost.value; @@ -364,7 +364,8 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const { - if (m_gasCostsMaps.contains(_documentId)) + auto ite = m_gasCostsMaps.find(_documentId); + if (ite != m_gasCostsMaps.end()) { auto sourceMapIter = m_gasCostsMaps.find(_documentId); return sourceMapIter.value(); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index f5a170da6..7cc9d3477 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -137,7 +137,7 @@ class GasMap: public QObject Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) public: - GasMap(int _start, int _end, QString _gas, bool _isInfinite): m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) {} + GasMap(int _start, int _end, QString _gas, bool _isInfinite): m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } int m_start; int m_end; diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 7d68f4032..d1ecf0380 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -215,7 +215,6 @@ var gasCosts = null; setGasCosts = function(_gasCosts) { gasCosts = JSON.parse(_gasCosts); - if (showingGasEstimation) { displayGasEstimation(false); @@ -278,12 +277,13 @@ var gasAnnotation; function listenMouseOver(e) { var node = e.target || e.srcElement; - if (node) { - if (!gasAnnotation && node.className && node.className.indexOf("CodeMirror-gasCosts") !== -1) + if (node) + { + if (node.className && node.className.indexOf("CodeMirror-gasCosts") !== -1) { if (gasAnnotation) gasAnnotation.clear(); - var cl = node.className.split(" ")[1]; + var cl = getClass(node); var gasTitle = gasMarkRef[cl].value.isInfinite ? "infinite" : gasMarkRef[cl].value.gas; gasTitle = gasTitle + " gas"; gasAnnotation = editor.addLineWidget(gasMarkRef[cl].line + 1, makeGasCostMarker(gasTitle), { coverGutter: false, above: true }); @@ -296,7 +296,19 @@ function listenMouseOver(e) } } +function getClass(node) +{ + var classes = node.className.split(" "); + for (var k in classes) + { + if (classes[k].indexOf("CodeMirror-gasCosts") !== -1) + return classes[k]; + } + return ""; +} + // blue => red ["#1515ED", "#1714EA", "#1914E8", "#1B14E6", "#1D14E4", "#1F14E2", "#2214E0", "#2414DE", "#2614DC", "#2813DA", "#2A13D8", "#2D13D6", "#2F13D4", "#3113D2", "#3313D0", "#3513CE", "#3713CC", "#3A12CA", "#3C12C8", "#3E12C6", "#4012C4", "#4212C2", "#4512C0", "#4712BE", "#4912BC", "#4B11BA", "#4D11B8", "#4F11B6", "#5211B4", "#5411B2", "#5611B0", "#5811AE", "#5A11AC", "#5D11AA", "#5F10A7", "#6110A5", "#6310A3", "#6510A1", "#67109F", "#6A109D", "#6C109B", "#6E1099", "#700F97", "#720F95", "#750F93", "#770F91", "#790F8F", "#7B0F8D", "#7D0F8B", "#7F0F89", "#820E87", "#840E85", "#860E83", "#880E81", "#8A0E7F", "#8D0E7D", "#8F0E7B", "#910E79", "#930D77", "#950D75", "#970D73", "#9A0D71", "#9C0D6F", "#9E0D6D", "#A00D6B", "#A20D69", "#A50D67", "#A70C64", "#A90C62", "#AB0C60", "#AD0C5E", "#AF0C5C", "#B20C5A", "#B40C58", "#B60C56", "#B80B54", "#BA0B52", "#BD0B50", "#BF0B4E", "#C10B4C", "#C30B4A", "#C50B48", "#C70B46", "#CA0A44", "#CC0A42", "#CE0A40", "#D00A3E", "#D20A3C", "#D50A3A", "#D70A38", "#D90A36", "#DB0934", "#DD0932", "#DF0930", "#E2092E", "#E4092C", "#E6092A", "#E80928", "#EA0926", "#ED0924"] /* green => red */ var colorGradient = ["#429C27", "#439A26", "#449926", "#469726", "#479626", "#489525", "#4A9325", "#4B9225", "#4D9025", "#4E8F25", "#4F8E24", "#518C24", "#528B24", "#548924", "#558824", "#568723", "#588523", "#598423", "#5B8223", "#5C8122", "#5D8022", "#5F7E22", "#607D22", "#627B22", "#637A21", "#647921", "#667721", "#677621", "#697421", "#6A7320", "#6B7220", "#6D7020", "#6E6F20", "#706E20", "#716C1F", "#726B1F", "#74691F", "#75681F", "#76671E", "#78651E", "#79641E", "#7B621E", "#7C611E", "#7D601D", "#7F5E1D", "#805D1D", "#825B1D", "#835A1D", "#84591C", "#86571C", "#87561C", "#89541C", "#8A531B", "#8B521B", "#8D501B", "#8E4F1B", "#904D1B", "#914C1A", "#924B1A", "#94491A", "#95481A", "#97461A", "#984519", "#994419", "#9B4219", "#9C4119", "#9E4019", "#9F3E18", "#A03D18", "#A23B18", "#A33A18", "#A43917", "#A63717", "#A73617", "#A93417", "#AA3317", "#AB3216", "#AD3016", "#AE2F16", "#B02D16", "#B12C16", "#B22B15", "#B42915", "#B52815", "#B72615", "#B82514", "#B92414", "#BB2214", "#BC2114", "#BE1F14", "#BF1E13", "#C01D13", "#C21B13", "#C31A13", "#C51813", "#C61712", "#C71612", "#C91412", "#CA1312", "#CC1212"] + editor.setOption("extraKeys", extraKeys); From eca68b12587f9f6c2b2203c191b929b05b289ba9 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 15 May 2015 15:14:23 +0200 Subject: [PATCH 05/70] small change --- mix/qml/html/codeeditor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index d1ecf0380..6499922ae 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -283,7 +283,7 @@ function listenMouseOver(e) { if (gasAnnotation) gasAnnotation.clear(); - var cl = getClass(node); + var cl = getGasCostClass(node); var gasTitle = gasMarkRef[cl].value.isInfinite ? "infinite" : gasMarkRef[cl].value.gas; gasTitle = gasTitle + " gas"; gasAnnotation = editor.addLineWidget(gasMarkRef[cl].line + 1, makeGasCostMarker(gasTitle), { coverGutter: false, above: true }); @@ -296,7 +296,7 @@ function listenMouseOver(e) } } -function getClass(node) +function getGasCostClass(node) { var classes = node.className.split(" "); for (var k in classes) From 51ddf29763bb61cdd60d96589129647bfbe27290 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 15 May 2015 15:42:23 +0200 Subject: [PATCH 06/70] small changes --- mix/CodeModel.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 7a0325b7a..137188e40 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -350,13 +350,13 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) StructuralGasEstimator estimator; std::map gasCosts = estimator.breakToStatementLevel(estimator.performEstimation(*items, std::vector({&sourceUnit})), {&sourceUnit}); - for (auto gasIte = gasCosts.begin(); gasIte != gasCosts.end(); ++gasIte) + for (auto gasItem = gasCosts.begin(); gasItem != gasCosts.end(); ++gasItem) { - SourceLocation const& location = gasIte->first->getLocation(); - GasMeter::GasConsumption cost = gasIte->second; + SourceLocation const& location = gasItem->first->getLocation(); + GasMeter::GasConsumption cost = gasItem->second; std::stringstream v; v << cost.value; - GasMap* gas = new GasMap(location.start, location.end, QString::fromStdString(v.str()), gasIte->second.isInfinite); + GasMap* gas = new GasMap(location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite); m_gasCostsMaps.find(sourceName).value().push_back(QVariant::fromValue(gas)); } } @@ -364,12 +364,9 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const { - auto ite = m_gasCostsMaps.find(_documentId); - if (ite != m_gasCostsMaps.end()) - { - auto sourceMapIter = m_gasCostsMaps.find(_documentId); - return sourceMapIter.value(); - } + auto gasIter = m_gasCostsMaps.find(_documentId); + if (gasIter != m_gasCostsMaps.end()) + return gasIter.value(); else return QVariantList(); } From 16ce50dded9a63296dc502b3edd938f81e3ad301 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 May 2015 10:49:10 +0200 Subject: [PATCH 07/70] add GasMapWrapper --- mix/CodeModel.cpp | 44 ++++++++++++++++++++++++++++++++------------ mix/CodeModel.h | 27 ++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 137188e40..e622d7973 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -333,42 +333,36 @@ void CodeModel::runCompilationJob(int _jobId) void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) { - m_gasCostsMaps.clear(); + m_gasCostsMaps->deleteLater(); + m_gasCostsMaps = new GasMapWrapper(this); for (std::string n: _cs.getContractNames()) { ContractDefinition const& contractDefinition = _cs.getContractDefinition(n); QString sourceName = QString::fromStdString(*contractDefinition.getLocation().sourceName); - if (!m_gasCostsMaps.contains(sourceName)) - m_gasCostsMaps.insert(sourceName, QVariantList()); + if (!m_gasCostsMaps->contains(sourceName)) + m_gasCostsMaps->insert(sourceName, QVariantList()); if (!contractDefinition.isFullyImplemented()) continue; dev::solidity::SourceUnit const& sourceUnit = _cs.getAST(*contractDefinition.getLocation().sourceName); AssemblyItems const* items = _cs.getRuntimeAssemblyItems(n); - StructuralGasEstimator estimator; std::map gasCosts = estimator.breakToStatementLevel(estimator.performEstimation(*items, std::vector({&sourceUnit})), {&sourceUnit}); - for (auto gasItem = gasCosts.begin(); gasItem != gasCosts.end(); ++gasItem) { SourceLocation const& location = gasItem->first->getLocation(); GasMeter::GasConsumption cost = gasItem->second; std::stringstream v; v << cost.value; - GasMap* gas = new GasMap(location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite); - m_gasCostsMaps.find(sourceName).value().push_back(QVariant::fromValue(gas)); + m_gasCostsMaps->push(sourceName, location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite); } } } QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const { - auto gasIter = m_gasCostsMaps.find(_documentId); - if (gasIter != m_gasCostsMaps.end()) - return gasIter.value(); - else - return QVariantList(); + return m_gasCostsMaps->gasCostsByDocId(_documentId); } void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames) @@ -560,3 +554,29 @@ QString CodeModel::resolveFunctionName(dev::SourceLocation const& _location) } return QString(); } + +void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite) +{ + GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, this); + m_gasMaps.find(_source).value().push_back(QVariant::fromValue(gas)); +} + +bool GasMapWrapper::contains(QString _key) +{ + return m_gasMaps.contains(_key); +} + +void GasMapWrapper::insert(QString _source, QVariantList _variantList) +{ + m_gasMaps.insert(_source, _variantList); +} + +QVariantList GasMapWrapper::gasCostsByDocId(QString _source) +{ + auto gasIter = m_gasMaps.find(_source); + if (gasIter != m_gasMaps.end()) + return gasIter.value(); + else + return QVariantList(); +} + diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 7cc9d3477..ca9658786 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -127,6 +127,26 @@ struct SourceMap LocationMap functions; }; +using SourceMaps = QMap; //by source id +using GasCostsMaps = QMap; //gas cost by contract name + +class GasMapWrapper: public QObject +{ + Q_OBJECT + + Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT) + +public: + GasMapWrapper(QObject* _parent): QObject(_parent){} + void push(QString _source, int _start, int _end, QString _value, bool _isInfinite); + bool contains(QString _key); + void insert(QString _source, QVariantList _variantList); + QVariantList gasCostsByDocId(QString _source); + +private: + GasCostsMaps m_gasMaps; +}; + class GasMap: public QObject { Q_OBJECT @@ -137,7 +157,7 @@ class GasMap: public QObject Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) public: - GasMap(int _start, int _end, QString _gas, bool _isInfinite): m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } + GasMap(int _start, int _end, QString _gas, bool _isInfinite, QObject _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } int m_start; int m_end; @@ -145,9 +165,6 @@ public: bool m_isInfinite; }; -using SourceMaps = QMap; //by source id -using GasCostsMaps = QMap; //gas cost by contract name - /// Code compilation model. Compiles contracts in background an provides compiled contract data class CodeModel: public QObject { @@ -227,7 +244,7 @@ private: mutable dev::Mutex x_contractMap; ContractMap m_contractMap; SourceMaps m_sourceMaps; - GasCostsMaps m_gasCostsMaps; + GasMapWrapper* m_gasCostsMaps; std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; From 2c665ea0f9de2f8b4c4438d787b21b6f6e39be97 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 May 2015 11:06:34 +0200 Subject: [PATCH 08/70] small changes --- mix/CodeModel.cpp | 3 ++- mix/CodeModel.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index e622d7973..03ae828e0 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -333,7 +333,8 @@ void CodeModel::runCompilationJob(int _jobId) void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) { - m_gasCostsMaps->deleteLater(); + if (m_gasCostsMaps) + m_gasCostsMaps->deleteLater(); m_gasCostsMaps = new GasMapWrapper(this); for (std::string n: _cs.getContractNames()) { diff --git a/mix/CodeModel.h b/mix/CodeModel.h index ca9658786..9295c38f0 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -244,7 +244,7 @@ private: mutable dev::Mutex x_contractMap; ContractMap m_contractMap; SourceMaps m_sourceMaps; - GasMapWrapper* m_gasCostsMaps; + GasMapWrapper* m_gasCostsMaps = 0; std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; From 9111b31ca7721feaa029c2398741a6f34a2c1361 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 May 2015 11:18:01 +0200 Subject: [PATCH 09/70] small changes --- mix/CodeModel.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 03ae828e0..b0edb20f9 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -363,7 +363,10 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const { - return m_gasCostsMaps->gasCostsByDocId(_documentId); + if (m_gasCostsMaps) + return m_gasCostsMaps->gasCostsByDocId(_documentId); + else + return QVariantList(); } void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames) From 09f13ce1a6a50cc8929212e194434789f7f1768a Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 May 2015 14:39:07 +0200 Subject: [PATCH 10/70] small change --- mix/CodeModel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 9295c38f0..95c44febe 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -157,7 +157,7 @@ class GasMap: public QObject Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) public: - GasMap(int _start, int _end, QString _gas, bool _isInfinite, QObject _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } + GasMap(int _start, int _end, QString _gas, bool _isInfinite, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } int m_start; int m_end; From 798012bfc89cf0e5806824b6253065e63ee3dfb1 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 May 2015 17:02:54 +0200 Subject: [PATCH 11/70] second error location --- mix/CodeModel.cpp | 35 ++++++++++++++++-------- mix/CodeModel.h | 3 ++- mix/qml/CodeEditorView.qml | 2 +- mix/qml/WebCodeEditor.qml | 21 +++++++++++---- mix/qml/html/cm/errorannotation.js | 26 +++++++++--------- mix/qml/html/cm/solidityToken.js | 2 +- mix/qml/html/codeeditor.js | 43 ++++++++++++++++++++++-------- 7 files changed, 89 insertions(+), 43 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 5c6ec07c0..82f9291df 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -309,24 +309,37 @@ void CodeModel::runCompilationJob(int _jobId) } catch (dev::Exception const& _exception) { - std::ostringstream error; + std::stringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); QString message = QString::fromStdString(error.str()); - QString sourceName; - if (SourceLocation const* location = boost::get_error_info(_exception)) - { - if (location->sourceName) - sourceName = QString::fromStdString(*location->sourceName); - if (!sourceName.isEmpty()) - if (CompiledContract* contract = contractByDocumentId(sourceName)) - message = message.replace(sourceName, contract->contract()->name()); //substitute the location to match our contract names - } - compilationError(message, sourceName); + QVariantMap firstLocation; + QVariantMap secondLocation; + if (SourceLocation const* first = boost::get_error_info(_exception)) + firstLocation = resolveCompilationErrorLocation(cs, *first); + if (SecondarySourceLocation const* second = boost::get_error_info(_exception)) + secondLocation = resolveCompilationErrorLocation(cs, second->infos.front().second); + compilationError(message, firstLocation, secondLocation); } m_compiling = false; emit stateChanged(); } +QVariantMap CodeModel::resolveCompilationErrorLocation(CompilerStack const& _compiler, SourceLocation const& _location) +{ + std::tuple pos = _compiler.positionFromSourceLocation(_location); + QVariantMap startError; + startError.insert("line", std::get<0>(pos) - 1); + startError.insert("column", std::get<1>(pos) - 1); + QVariantMap endError; + endError.insert("line", std::get<2>(pos) - 1); + endError.insert("column", std::get<3>(pos) - 1); + QVariantMap error; + error.insert("start", startError); + error.insert("end", endError); + error.insert("source", QString::fromStdString(*_location.sourceName)); + return error; +} + void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames) { Guard pl(x_pendingContracts); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index a0b03951f..05d013f9a 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -175,7 +175,7 @@ signals: /// Emitted on compilation complete void compilationComplete(); /// Emitted on compilation error - void compilationError(QString _error, QString _sourceName); + void compilationError(QString _error, QVariantMap _firstErrorLoc, QVariantMap _secondErrorLoc); /// Internal signal used to transfer compilation job to background thread void scheduleCompilationJob(int _jobId); /// Emitted if there are any changes in the code model @@ -198,6 +198,7 @@ private: void stop(); void releaseContracts(); void collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames); + QVariantMap resolveCompilationErrorLocation(dev::solidity::CompilerStack const& _cs, dev::SourceLocation const& _location); std::atomic m_compiling; mutable dev::Mutex x_contractMap; diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index bb7e203bf..8ebb7319f 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -173,7 +173,7 @@ Item { Connections { target: codeModel onCompilationError: { - sourceInError = _sourceName; + sourceInError = _firstErrorLoc.source; } onCompilationComplete: { sourceInError = ""; diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index 38f2327b1..49a0576cc 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -137,17 +137,28 @@ Item { editorBrowser.runJavaScript("compilationComplete()", function(result) { }); } - function compilationError(error, sourceName) + function compilationError(error, firstLocation, secondLocation) { - if (sourceName !== parent.sourceName) + console.log("current " + parent.sourceName); + console.log("source " + firstLocation.source); + if (firstLocation.source !== parent.sourceName && secondLocation.source !== parent.sourceName) return; if (!editorBrowser || !error) return; - var errorInfo = ErrorLocationFormater.extractErrorInfo(error, false); - if (errorInfo.line && errorInfo.column) - editorBrowser.runJavaScript("compilationError('" + errorInfo.line + "', '" + errorInfo.column + "', '" + errorInfo.errorDetail + "')", function(result) { }); + if (firstLocation.start.line) + { + var detail = error.split('\n')[0]; + var reg = detail.match(/:\d+:\d+:/g); + if (reg !== null) + detail = detail.replace(reg[0], ""); + editorBrowser.runJavaScript("compilationError('" + JSON.stringify(firstLocation) + "', '" + JSON.stringify(secondLocation) + "', '" + detail + "')", function(result){}); + } else + { + console.log("e d qml"); editorBrowser.runJavaScript("compilationComplete()", function(result) { }); + } + } Timer diff --git a/mix/qml/html/cm/errorannotation.js b/mix/qml/html/cm/errorannotation.js index 071f0e0d8..f5266d4dc 100644 --- a/mix/qml/html/cm/errorannotation.js +++ b/mix/qml/html/cm/errorannotation.js @@ -1,42 +1,39 @@ -function ErrorAnnotation(editor, line, column, content) +function ErrorAnnotation(editor, location, content) { + this.location = JSON.parse(location); this.opened = false; - this.line = line; - this.column = column; + this.rawContent = content; this.content = content.replace("Contract Error:", ""); this.editor = editor; this.errorMark = null; this.lineWidget = null; this.init(); - this.open(); + if (this.content) + this.open(); } ErrorAnnotation.prototype.init = function() { - var separators = [';', ',', '\\\(', '\\\{', '\\\}', '\\\)', ':']; - var errorPart = editor.getLine(this.line).substring(this.column); - var incrMark = this.column + errorPart.split(new RegExp(separators.join('|'), 'g'))[0].length; - if (incrMark === this.column) - incrMark = this.column + 1; - this.errorMark = editor.markText({ line: this.line, ch: this.column }, { line: this.line, ch: incrMark }, { className: "CodeMirror-errorannotation", inclusiveRight: true }); + this.errorMark = editor.markText({ line: this.location.start.line, ch: this.location.start.column }, { line: this.location.end.line, ch: this.location.end.column }, { className: "CodeMirror-errorannotation", inclusiveRight: true }); } ErrorAnnotation.prototype.open = function() { - if (this.line) + if (this.location.start.line) { var node = document.createElement("div"); node.id = "annotation" node.innerHTML = this.content; node.className = "CodeMirror-errorannotation-context"; - this.lineWidget = this.editor.addLineWidget(this.line, node, { coverGutter: false }); + this.lineWidget = this.editor.addLineWidget(this.location.start.line, node, { coverGutter: false }); this.opened = true; } } ErrorAnnotation.prototype.close = function() { - this.lineWidget.clear(); + if (this.lineWidget) + this.lineWidget.clear(); this.opened = false; } @@ -47,3 +44,6 @@ ErrorAnnotation.prototype.destroy = function() if (this.errorMark) this.errorMark.clear(); } + + + diff --git a/mix/qml/html/cm/solidityToken.js b/mix/qml/html/cm/solidityToken.js index d8e588a10..d803697cb 100644 --- a/mix/qml/html/cm/solidityToken.js +++ b/mix/qml/html/cm/solidityToken.js @@ -5,7 +5,7 @@ function solCurrency() function solKeywords() { - return { "break": true, "case": true, "constant": true, "continue": true, "contract": true, "default": true, "do": true, "else": true, "event": true, "external": true, "is": true, "indexed": true, "for": true, "function": true, "if": true, "import": true, "mapping": true, "modifier": true, "new": true, "public": true, "private": true, "internal": true, "return": true, "returns": true, "struct": true, "switch": true, "var": true, "while": true, "enum": true }; + return { "delete": true, "break": true, "case": true, "constant": true, "continue": true, "contract": true, "default": true, "do": true, "else": true, "event": true, "external": true, "is": true, "indexed": true, "for": true, "function": true, "if": true, "import": true, "mapping": true, "modifier": true, "new": true, "public": true, "private": true, "internal": true, "return": true, "returns": true, "struct": true, "switch": true, "var": true, "while": true, "enum": true }; } function solStdContract() diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index d25fbd091..4c8af5888 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -158,30 +158,43 @@ showWarning = function(content) } var annotation = null; +var secondaryAnnotation = null; var compilationCompleteBool = true; -compilationError = function(line, column, content) +compilationError = function(location, secondLocation, error) { compilationCompleteBool = false; window.setTimeout(function(){ if (compilationCompleteBool) return; - line = parseInt(line); - column = parseInt(column); - if (line > 0) - line = line - 1; - if (column > 0) - column = column - 1; + var loc = JSON.parse(location); if (annotation == null) - annotation = new ErrorAnnotation(editor, line, column, content); - else if (annotation.line !== line || annotation.column !== column || annotation.content !== content) + { + annotation = new ErrorAnnotation(editor, location, error); + if (secondLocation.start) + secondaryAnnotation = new ErrorAnnotation(editor, secondLocation, ""); + } + else if (annotation.location.start.line !== loc.start.line || annotation.location.start.column !== loc.start.column || annotation.rawContent !== error) { annotation.destroy(); - annotation = new ErrorAnnotation(editor, line, column, content); + annotation = new ErrorAnnotation(editor, location, error); + if (secondaryAnnotation) + secondaryAnnotation.destroy(); + secondaryAnnotation = new ErrorAnnotation(editor, secondLocation, ""); } }, 500) } +formatSource = function(line, column) +{ + line = parseInt(line); + column = parseInt(column); + if (line > 0) + line = line - 1; + if (column > 0) + column = column - 1; +} + compilationComplete = function() { if (annotation !== null) @@ -189,12 +202,20 @@ compilationComplete = function() annotation.destroy(); annotation = null; } + + if (secondaryAnnotation !== null) + { + secondaryAnnotation.destroy(); + secondaryAnnotation = null; + } + compilationCompleteBool = true; + console.log("end"); } goToCompilationError = function() { - editor.setCursor(annotation.line, annotation.column) + editor.setCursor(annotation.start.line, annotation.start.column) } setFontSize = function(size) From 352ec1153632903f7c0396f8e32403060fbcf536 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 May 2015 19:28:31 +0200 Subject: [PATCH 12/70] add list of second errorannotation instead of single item. --- mix/CodeModel.cpp | 9 ++-- mix/CodeModel.h | 2 +- mix/qml/CodeEditorView.qml | 2 +- mix/qml/WebCodeEditor.qml | 38 ++++++++------- mix/qml/html/cm/errorannotation.js | 2 +- mix/qml/html/codeeditor.js | 75 ++++++++++++------------------ test/libethereum/stateOriginal.cpp | 2 +- 7 files changed, 61 insertions(+), 69 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 82f9291df..769497dcd 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -313,12 +313,15 @@ void CodeModel::runCompilationJob(int _jobId) solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); QString message = QString::fromStdString(error.str()); QVariantMap firstLocation; - QVariantMap secondLocation; + QVariantList secondLocations; if (SourceLocation const* first = boost::get_error_info(_exception)) firstLocation = resolveCompilationErrorLocation(cs, *first); if (SecondarySourceLocation const* second = boost::get_error_info(_exception)) - secondLocation = resolveCompilationErrorLocation(cs, second->infos.front().second); - compilationError(message, firstLocation, secondLocation); + { + for (auto const& c: second->infos) + secondLocations.push_back(resolveCompilationErrorLocation(cs, c.second)); + } + compilationError(message, firstLocation, secondLocations); } m_compiling = false; emit stateChanged(); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 05d013f9a..2510b4248 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -175,7 +175,7 @@ signals: /// Emitted on compilation complete void compilationComplete(); /// Emitted on compilation error - void compilationError(QString _error, QVariantMap _firstErrorLoc, QVariantMap _secondErrorLoc); + void compilationError(QString _error, QVariantMap _firstErrorLoc, QVariantList _secondErrorLoc); /// Internal signal used to transfer compilation job to background thread void scheduleCompilationJob(int _jobId); /// Emitted if there are any changes in the code model diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 8ebb7319f..1a5e3f0f8 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -74,7 +74,7 @@ Item { }); } editor.document = document; - editor.sourceName = document.documentId; + editor.setSourceName(document.documentId); editor.setFontSize(editorSettings.fontSize); editor.setText(data, document.syntaxMode); editor.changeGeneration(); diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index 49a0576cc..af3eda094 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -83,6 +83,13 @@ Item { editorBrowser.runJavaScript("setFontSize(" + size + ")", function(result) {}); } + function setSourceName(sourceName) + { + sourceName = sourceName; + if (initialized && editorBrowser) + editorBrowser.runJavaScript("setSourceName('" + sourceName + "')", function(result) {}); + } + Clipboard { id: clipboard @@ -137,28 +144,23 @@ Item { editorBrowser.runJavaScript("compilationComplete()", function(result) { }); } - function compilationError(error, firstLocation, secondLocation) + function compilationError(error, firstLocation, secondLocations) { - console.log("current " + parent.sourceName); - console.log("source " + firstLocation.source); - if (firstLocation.source !== parent.sourceName && secondLocation.source !== parent.sourceName) - return; if (!editorBrowser || !error) return; - if (firstLocation.start.line) - { - var detail = error.split('\n')[0]; - var reg = detail.match(/:\d+:\d+:/g); - if (reg !== null) - detail = detail.replace(reg[0], ""); - editorBrowser.runJavaScript("compilationError('" + JSON.stringify(firstLocation) + "', '" + JSON.stringify(secondLocation) + "', '" + detail + "')", function(result){}); - } - else - { - console.log("e d qml"); - editorBrowser.runJavaScript("compilationComplete()", function(result) { }); - } + var detail = error.split('\n')[0]; + var reg = detail.match(/:\d+:\d+:/g); + if (reg !== null) + detail = detail.replace(reg[0], ""); + displayErrorAnnotations(firstLocation, detail, "first"); + for (var k in secondLocations) + displayErrorAnnotations(secondLocations[k], detail, "second"); + } + function displayErrorAnnotations(location, detail, type) + { + //if (location.source === parent.sourceName) + editorBrowser.runJavaScript("compilationError('" + JSON.stringify(location) + "', '" + detail + "', '" + type + "')", function(result){}); } Timer diff --git a/mix/qml/html/cm/errorannotation.js b/mix/qml/html/cm/errorannotation.js index f5266d4dc..a8cdb6fe6 100644 --- a/mix/qml/html/cm/errorannotation.js +++ b/mix/qml/html/cm/errorannotation.js @@ -1,6 +1,6 @@ function ErrorAnnotation(editor, location, content) { - this.location = JSON.parse(location); + this.location = location; this.opened = false; this.rawContent = content; this.content = content.replace("Contract Error:", ""); diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index 4c8af5888..4cf443b72 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -8,6 +8,7 @@ var editor = CodeMirror(document.body, { styleSelectedText: true }); var ternServer; +var sourceName = ""; editor.setOption("theme", "inkpot"); editor.setOption("indentUnit", 4); @@ -157,65 +158,46 @@ showWarning = function(content) debugWarning = editor.addLineWidget(0, node, { coverGutter: false, above: true }); } -var annotation = null; -var secondaryAnnotation = null; +var annotations = []; var compilationCompleteBool = true; -compilationError = function(location, secondLocation, error) +compilationError = function(location, error, type) { compilationCompleteBool = false; - window.setTimeout(function(){ - if (compilationCompleteBool) - return; - - var loc = JSON.parse(location); - if (annotation == null) - { - annotation = new ErrorAnnotation(editor, location, error); - if (secondLocation.start) - secondaryAnnotation = new ErrorAnnotation(editor, secondLocation, ""); - } - else if (annotation.location.start.line !== loc.start.line || annotation.location.start.column !== loc.start.column || annotation.rawContent !== error) - { - annotation.destroy(); - annotation = new ErrorAnnotation(editor, location, error); - if (secondaryAnnotation) - secondaryAnnotation.destroy(); - secondaryAnnotation = new ErrorAnnotation(editor, secondLocation, ""); - } - }, 500) + if (compilationCompleteBool) + return; + location = JSON.parse(location); + if (location.start.line) + ensureAnnotation(location, error, type); } -formatSource = function(line, column) +ensureAnnotation = function(location, error, type) { - line = parseInt(line); - column = parseInt(column); - if (line > 0) - line = line - 1; - if (column > 0) - column = column - 1; + for (var k in annotations) + { + if (annotations[k].annotation.location.start.line === location.start.line) + { + annotations[k].annotation.destroy(); + annotations.splice(k, 1); + break; + } + } + if (type === "second") + error = ""; + annotations.push({ "type": type, "annotation": new ErrorAnnotation(editor, location, error)}); } compilationComplete = function() { - if (annotation !== null) - { - annotation.destroy(); - annotation = null; - } - - if (secondaryAnnotation !== null) - { - secondaryAnnotation.destroy(); - secondaryAnnotation = null; - } - + for (var k in annotations) + annotations[k].annotation.destroy(); + annotations.length = 0; compilationCompleteBool = true; - console.log("end"); } goToCompilationError = function() { - editor.setCursor(annotation.start.line, annotation.start.column) + if (annotations.length > 0) + editor.setCursor(annotations[0].annotation.location.start.line, annotations[0].annotation.location.start.column) } setFontSize = function(size) @@ -224,5 +206,10 @@ setFontSize = function(size) editor.refresh(); } +setSourceName = function(_sourceName) +{ + sourceName = _sourceName; +} + editor.setOption("extraKeys", extraKeys); diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 82d6288d6..bad0cf223 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +//#include #include #include "../TestHelper.h" using namespace std; From 4f67ec63c7b44abafcce5a6cd1202417d4a0bfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 19 May 2015 10:19:14 +0200 Subject: [PATCH 13/70] Do not override CMAKE_CXX_FLAGS in evmjit. --- evmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index a0e9c1f46..280fec212 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") From babebadc29f217033aca52bee78cf5af46290997 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 19 May 2015 10:33:56 +0200 Subject: [PATCH 14/70] replace sourceNamne by contractName --- mix/CodeModel.cpp | 87 +++++++++++++++++++++------------------ mix/qml/WebCodeEditor.qml | 21 +++++++--- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 769497dcd..9875ee1aa 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -45,7 +45,7 @@ using namespace dev::mix; const std::set c_predefinedContracts = - { "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" }; +{ "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" }; namespace @@ -56,7 +56,7 @@ class CollectLocalsVisitor: public ASTConstVisitor { public: CollectLocalsVisitor(QHash* _locals): - m_locals(_locals), m_functionScope(false) {} + m_locals(_locals), m_functionScope(false) {} private: LocationPair nodeLocation(ASTNode const& _node) @@ -96,7 +96,7 @@ class CollectLocationsVisitor: public ASTConstVisitor { public: CollectLocationsVisitor(SourceMap* _sourceMap): - m_sourceMap(_sourceMap) {} + m_sourceMap(_sourceMap) {} private: LocationPair nodeLocation(ASTNode const& _node) @@ -339,7 +339,14 @@ QVariantMap CodeModel::resolveCompilationErrorLocation(CompilerStack const& _com QVariantMap error; error.insert("start", startError); error.insert("end", endError); - error.insert("source", QString::fromStdString(*_location.sourceName)); + QString sourceName; + if (_location.sourceName) + sourceName = QString::fromStdString(*_location.sourceName); + error.insert("source", sourceName); + if (!sourceName.isEmpty()) + if (CompiledContract* contract = contractByDocumentId(sourceName)) + sourceName = contract->contract()->name(); //substitute the location to match our contract names + error.insert("contractName", sourceName); return error; } @@ -385,7 +392,7 @@ void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::v { //make sure there are no other contracts in the same source, otherwise it is not a rename if (!std::any_of(result.begin(),result.end(), [=](ContractMap::const_iterator::value_type _v) { return _v != contract && _v->documentId() == contract->documentId(); })) - prevContract = c.value(); + prevContract = c.value(); } } if (prevContract != nullptr && prevContract->contractInterface() != result[name]->contractInterface()) @@ -435,59 +442,59 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) switch (_type->getCategory()) { case Type::Category::Integer: - { - IntegerType const* it = dynamic_cast(_type); - r.size = it->getNumBits() / 8; - r.type = it->isAddress() ? SolidityType::Type::Address : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger; - } + { + IntegerType const* it = dynamic_cast(_type); + r.size = it->getNumBits() / 8; + r.type = it->isAddress() ? SolidityType::Type::Address : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger; + } break; case Type::Category::Bool: r.type = SolidityType::Type::Bool; break; case Type::Category::FixedBytes: - { - FixedBytesType const* b = dynamic_cast(_type); - r.type = SolidityType::Type::Bytes; - r.size = static_cast(b->getNumBytes()); - } + { + FixedBytesType const* b = dynamic_cast(_type); + r.type = SolidityType::Type::Bytes; + r.size = static_cast(b->getNumBytes()); + } break; case Type::Category::Contract: r.type = SolidityType::Type::Address; break; case Type::Category::Array: + { + ArrayType const* array = dynamic_cast(_type); + if (array->isByteArray()) + r.type = SolidityType::Type::Bytes; + else { - ArrayType const* array = dynamic_cast(_type); - if (array->isByteArray()) - r.type = SolidityType::Type::Bytes; - else - { - SolidityType elementType = nodeType(array->getBaseType().get()); - elementType.name = r.name; - r = elementType; - } - r.count = static_cast(array->getLength()); - r.dynamicSize = _type->isDynamicallySized(); - r.array = true; + SolidityType elementType = nodeType(array->getBaseType().get()); + elementType.name = r.name; + r = elementType; } + r.count = static_cast(array->getLength()); + r.dynamicSize = _type->isDynamicallySized(); + r.array = true; + } break; case Type::Category::Enum: - { - r.type = SolidityType::Type::Enum; - EnumType const* e = dynamic_cast(_type); - for(auto const& enumValue: e->getEnumDefinition().getMembers()) - r.enumNames.push_back(QString::fromStdString(enumValue->getName())); - } + { + r.type = SolidityType::Type::Enum; + EnumType const* e = dynamic_cast(_type); + for(auto const& enumValue: e->getEnumDefinition().getMembers()) + r.enumNames.push_back(QString::fromStdString(enumValue->getName())); + } break; case Type::Category::Struct: + { + r.type = SolidityType::Type::Struct; + StructType const* s = dynamic_cast(_type); + for(auto const& structMember: s->getMembers()) { - r.type = SolidityType::Type::Struct; - StructType const* s = dynamic_cast(_type); - for(auto const& structMember: s->getMembers()) - { - auto slotAndOffset = s->getStorageOffsetsOfMember(structMember.name); - r.members.push_back(SolidityDeclaration { QString::fromStdString(structMember.name), nodeType(structMember.type.get()), slotAndOffset.first, slotAndOffset.second }); - } + auto slotAndOffset = s->getStorageOffsetsOfMember(structMember.name); + r.members.push_back(SolidityDeclaration { QString::fromStdString(structMember.name), nodeType(structMember.type.get()), slotAndOffset.first, slotAndOffset.second }); } + } break; case Type::Category::Function: case Type::Category::IntegerConstant: diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index af3eda094..32e62d584 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -83,9 +83,9 @@ Item { editorBrowser.runJavaScript("setFontSize(" + size + ")", function(result) {}); } - function setSourceName(sourceName) + function setSourceName(_sourceName) { - sourceName = sourceName; + sourceName = _sourceName; if (initialized && editorBrowser) editorBrowser.runJavaScript("setSourceName('" + sourceName + "')", function(result) {}); } @@ -148,19 +148,28 @@ Item { { if (!editorBrowser || !error) return; + + var lineError = firstLocation.start.line + 1; + var errorOrigin = "source error in " + firstLocation.contractName + " line " + lineError + var secondErrorDetail = " Secondary sources: "; + for (var k in secondLocations) + { + lineError = secondLocations[k].start.line + 1; + secondErrorDetail += secondLocations[k].contractName + " line " + lineError + ", "; + displayErrorAnnotations(secondLocations[k], errorOrigin, "second"); + } var detail = error.split('\n')[0]; var reg = detail.match(/:\d+:\d+:/g); if (reg !== null) detail = detail.replace(reg[0], ""); + detail += secondErrorDetail; displayErrorAnnotations(firstLocation, detail, "first"); - for (var k in secondLocations) - displayErrorAnnotations(secondLocations[k], detail, "second"); } function displayErrorAnnotations(location, detail, type) { - //if (location.source === parent.sourceName) - editorBrowser.runJavaScript("compilationError('" + JSON.stringify(location) + "', '" + detail + "', '" + type + "')", function(result){}); + if (location.source === parent.sourceName) + editorBrowser.runJavaScript("compilationError('" + JSON.stringify(location) + "', '" + detail + "', '" + type + "')", function(result){}); } Timer From 996d340d493360ad0a1c4c635b0ae800357fff97 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 19 May 2015 11:26:52 +0200 Subject: [PATCH 15/70] remove JavaScript ownership --- mix/CodeModel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 95c44febe..994e9936a 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -157,7 +157,7 @@ class GasMap: public QObject Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) public: - GasMap(int _start, int _end, QString _gas, bool _isInfinite, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); } + GasMap(int _start, int _end, QString _gas, bool _isInfinite, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite) {} int m_start; int m_end; From e19ac5054c6331ffcec05e553087409d9235c53b Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 18 May 2015 22:14:03 +0200 Subject: [PATCH 16/70] use TrieHash for transactions and receipts roots --- libdevcore/Common.h | 3 +- libdevcore/CommonData.cpp | 12 ++++++++ libdevcore/CommonData.h | 1 + libdevcrypto/TrieHash.cpp | 29 +++++++++++-------- libdevcrypto/TrieHash.h | 5 ++-- libethereum/State.cpp | 20 ++++--------- test/libdevcrypto/trie.cpp | 57 ++++++++++++++++++++++++-------------- 7 files changed, 76 insertions(+), 51 deletions(-) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 95817e41c..240746302 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -86,8 +86,9 @@ extern const u256 UndefinedU256; // Map types. using StringMap = std::map; +using BytesMap = std::map; using u256Map = std::map; -using HexMap = std::map; +using HexMap = std::map; // Hash types. using StringHashMap = std::unordered_map; diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index 6cad29952..ba2b412fd 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -115,6 +115,18 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) return ret; } +bytes dev::asNibbles(bytes const& _s) +{ + std::vector ret; + ret.reserve(_s.size() * 2); + for (auto i: _s) + { + ret.push_back(i / 16); + ret.push_back(i % 16); + } + return ret; +} + bytes dev::asNibbles(std::string const& _s) { std::vector ret; diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 6c1f34667..29cc8e7c7 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -96,6 +96,7 @@ inline bytes asBytes(std::string const& _b) /// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). /// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1 bytes asNibbles(std::string const& _s); +bytes asNibbles(bytes const& _s); // Big-endian to/from host endian conversion functions. diff --git a/libdevcrypto/TrieHash.cpp b/libdevcrypto/TrieHash.cpp index 0b02ce77f..4c4ca620d 100644 --- a/libdevcrypto/TrieHash.cpp +++ b/libdevcrypto/TrieHash.cpp @@ -158,43 +158,48 @@ void hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i } } -h256 hash256(StringMap const& _s) +bytes rlp256(BytesMap const& _s) { // build patricia tree. if (_s.empty()) - return sha3(rlp("")); + return rlp(""); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(i->first)] = i->second; RLPStream s; hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); - return sha3(s.out()); + return s.out(); } -bytes rlp256(StringMap const& _s) +h256 hash256(BytesMap const& _s) +{ + return sha3(rlp256(_s)); +} + +h256 hash256(StringMap const& _s) { // build patricia tree. if (_s.empty()) - return rlp(""); + return sha3(rlp("")); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) - hexMap[asNibbles(i->first)] = i->second; + hexMap[asNibbles(i->first)] = bytes(i->second.begin(), i->second.end()); RLPStream s; - hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); - return s.out(); + hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); + return sha3(s.out()); } -h256 hash256(u256Map const& _s) +bytes rlp256(StringMap const& _s) { // build patricia tree. if (_s.empty()) - return sha3(rlp("")); + return rlp(""); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) - hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second)); + hexMap[asNibbles(i->first)] = bytes(i->second.begin(), i->second.end()); RLPStream s; hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); - return sha3(s.out()); + return s.out(); } /*h256 orderedTrieRoot(std::vector const& _data) diff --git a/libdevcrypto/TrieHash.h b/libdevcrypto/TrieHash.h index b0588fc38..46f9b1efb 100644 --- a/libdevcrypto/TrieHash.h +++ b/libdevcrypto/TrieHash.h @@ -27,9 +27,10 @@ namespace dev { +bytes rlp256(BytesMap const& _s); +h256 hash256(BytesMap const& _s); bytes rlp256(StringMap const& _s); h256 hash256(StringMap const& _s); -h256 hash256(u256Map const& _s); /*h256 orderedTrieRoot(std::vector const& _data); @@ -41,8 +42,6 @@ template inline h256 trieRootOver(unsigned _itemCount, T cons return hash256(m); }*/ -using bytesMap = std::unordered_map; - h256 orderedTrieRoot(std::vector const& _data); h256 orderedTrieRoot(std::vector const& _data); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index b9e548ea3..d586941b4 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -840,16 +840,8 @@ void State::commitToMine(BlockChain const& _bc) } } - // TODO: move over to using TrieHash - - - MemoryDB tm; - GenericTrieDB transactionsTrie(&tm); - transactionsTrie.init(); - - MemoryDB rm; - GenericTrieDB receiptsTrie(&rm); - receiptsTrie.init(); + BytesMap transactionsMap; + BytesMap receiptsMap; RLPStream txs; txs.appendList(m_transactions.size()); @@ -861,11 +853,11 @@ void State::commitToMine(BlockChain const& _bc) RLPStream receiptrlp; m_receipts[i].streamRLP(receiptrlp); - receiptsTrie.insert(&k.out(), &receiptrlp.out()); + receiptsMap.insert(std::make_pair(k.out(), receiptrlp.out())); RLPStream txrlp; m_transactions[i].streamRLP(txrlp); - transactionsTrie.insert(&k.out(), &txrlp.out()); + transactionsMap.insert(std::make_pair(k.out(), txrlp.out())); txs.appendRaw(txrlp.out()); } @@ -874,8 +866,8 @@ void State::commitToMine(BlockChain const& _bc) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = transactionsTrie.root(); - m_currentBlock.receiptsRoot = receiptsTrie.root(); + m_currentBlock.transactionsRoot = hash256(transactionsMap); + m_currentBlock.receiptsRoot = hash256(receiptsMap); m_currentBlock.logBloom = logBloom(); m_currentBlock.sha3Uncles = sha3(m_currentUncles); diff --git a/test/libdevcrypto/trie.cpp b/test/libdevcrypto/trie.cpp index ecfc515aa..00bccd241 100644 --- a/test/libdevcrypto/trie.cpp +++ b/test/libdevcrypto/trie.cpp @@ -294,15 +294,27 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) } } -inline h256 stringMapHash256(StringMap const& _s) +h256 stringMapHash256(StringMap const& _s) { - return hash256(_s); + //return hash256(_s); + BytesMap bytesMap; + for (auto const& _v: _s) + bytesMap.insert(std::make_pair(bytes(_v.first.begin(), _v.first.end()), bytes(_v.second.begin(), _v.second.end()))); + return hash256(bytesMap); +} + +bytes stringMapRlp256(StringMap const& _s) +{ + //return rlp256(_s); + BytesMap bytesMap; + for (auto const& _v: _s) + bytesMap.insert(std::make_pair(bytes(_v.first.begin(), _v.first.end()), bytes(_v.second.begin(), _v.second.end()))); + return rlp256(bytesMap); } BOOST_AUTO_TEST_CASE(moreTrieTests) { cnote << "Testing Trie more..."; -#if 0 // More tests... { MemoryDB m; @@ -311,7 +323,7 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) cout << t; cout << m; cout << t.root() << endl; - cout << hash256(StringMap()) << endl; + cout << stringMapHash256(StringMap()) << endl; t.insert(string("tesz"), string("test")); cout << t; @@ -336,7 +348,7 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) t.remove(string("test")); cout << m; cout << t.root() << endl; - cout << hash256(StringMap()) << endl; + cout << stringMapHash256(StringMap()) << endl; } { MemoryDB m; @@ -348,20 +360,23 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) cout << m; cout << t.root() << endl; cout << stringMapHash256({{"b", "B"}, {"a", "A"}}) << endl; - cout << RLP(rlp256({{"b", "B"}, {"a", "A"}})) << endl; + bytes r(stringMapRlp256({{"b", "B"}, {"a", "A"}})); + cout << RLP(r) << endl; } { MemTrie t; t.insert("dog", "puppy"); cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; + bytes r(t.rlp()); + cout << RLP(r) << endl; } { MemTrie t; t.insert("bed", "d"); t.insert("be", "e"); cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; + bytes r(t.rlp()); + cout << RLP(r) << endl; } { cout << hex << stringMapHash256({{"dog", "puppy"}, {"doe", "reindeer"}}) << endl; @@ -369,10 +384,10 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) t.insert("dog", "puppy"); t.insert("doe", "reindeer"); cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; + bytes r(t.rlp()); + cout << RLP(r) << endl; cout << toHex(t.rlp()) << endl; } -#endif { MemoryDB m; EnforceRefs r(m, true); @@ -387,16 +402,17 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) t.insert(a, b); s[a] = b; - /*cout << endl << "-------------------------------" << endl; + cout << endl << "-------------------------------" << endl; cout << a << " -> " << b << endl; cout << d; cout << m; cout << d.root() << endl; - cout << hash256(s) << endl;*/ + cout << hash256(s) << endl; + cout << stringMapHash256(s) << endl; BOOST_REQUIRE(d.check(true)); - BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); - BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); + BOOST_REQUIRE_EQUAL(t.hash256(), stringMapHash256(s)); + BOOST_REQUIRE_EQUAL(d.root(), stringMapHash256(s)); for (auto const& i: s) { (void)i; @@ -421,8 +437,8 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) BOOST_REQUIRE(d.check(true)); BOOST_REQUIRE(t.at(a).empty()); BOOST_REQUIRE(d.at(string(a)).empty()); - BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); - BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); + BOOST_REQUIRE_EQUAL(t.hash256(), stringMapHash256(s)); + BOOST_REQUIRE_EQUAL(d.root(), stringMapHash256(s)); for (auto const& i: s) { (void)i; @@ -493,7 +509,6 @@ BOOST_AUTO_TEST_CASE(trieLowerBound) BOOST_AUTO_TEST_CASE(trieStess) { cnote << "Stress-testing Trie..."; - if (0) { MemoryDB m; MemoryDB dm; @@ -512,8 +527,8 @@ BOOST_AUTO_TEST_CASE(trieStess) m[k] = v; t.insert(k, v); d.insert(k, v); - BOOST_REQUIRE_EQUAL(hash256(m), t.hash256()); - BOOST_REQUIRE_EQUAL(hash256(m), d.root()); + BOOST_REQUIRE_EQUAL(stringMapHash256(m), t.hash256()); + BOOST_REQUIRE_EQUAL(stringMapHash256(m), d.root()); BOOST_REQUIRE(d.check(true)); } while (!m.empty()) @@ -557,8 +572,8 @@ BOOST_AUTO_TEST_CASE(trieStess) cwarn << "Good?" << d2.root(); } BOOST_REQUIRE(d.check(true)); - BOOST_REQUIRE_EQUAL(hash256(m), t.hash256()); - BOOST_REQUIRE_EQUAL(hash256(m), d.root()); + BOOST_REQUIRE_EQUAL(stringMapHash256(m), t.hash256()); + BOOST_REQUIRE_EQUAL(stringMapHash256(m), d.root()); } } } From 4e358001acd9f478d2e69b16794cec4832afb1fa Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 19 May 2015 10:39:33 +0200 Subject: [PATCH 17/70] orderedTrieRoot testing --- libdevcore/CommonData.cpp | 14 +--------- libdevcore/CommonData.h | 3 +-- libdevcrypto/TrieHash.cpp | 55 ++++++-------------------------------- libdevcrypto/TrieHash.h | 10 +++---- libethcore/BlockInfo.cpp | 12 +-------- test/libdevcrypto/trie.cpp | 3 --- 6 files changed, 15 insertions(+), 82 deletions(-) diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index ba2b412fd..f8d8c172f 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -115,19 +115,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) return ret; } -bytes dev::asNibbles(bytes const& _s) -{ - std::vector ret; - ret.reserve(_s.size() * 2); - for (auto i: _s) - { - ret.push_back(i / 16); - ret.push_back(i % 16); - } - return ret; -} - -bytes dev::asNibbles(std::string const& _s) +bytes dev::asNibbles(bytesConstRef const& _s) { std::vector ret; ret.reserve(_s.size() * 2); diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 29cc8e7c7..702f1f808 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -95,8 +95,7 @@ inline bytes asBytes(std::string const& _b) /// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). /// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1 -bytes asNibbles(std::string const& _s); -bytes asNibbles(bytes const& _s); +bytes asNibbles(bytesConstRef const& _s); // Big-endian to/from host endian conversion functions. diff --git a/libdevcrypto/TrieHash.cpp b/libdevcrypto/TrieHash.cpp index 4c4ca620d..0f2d68b91 100644 --- a/libdevcrypto/TrieHash.cpp +++ b/libdevcrypto/TrieHash.cpp @@ -165,7 +165,7 @@ bytes rlp256(BytesMap const& _s) return rlp(""); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) - hexMap[asNibbles(i->first)] = i->second; + hexMap[asNibbles(bytesConstRef(&i->first))] = i->second; RLPStream s; hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); return s.out(); @@ -176,61 +176,22 @@ h256 hash256(BytesMap const& _s) return sha3(rlp256(_s)); } -h256 hash256(StringMap const& _s) -{ - // build patricia tree. - if (_s.empty()) - return sha3(rlp("")); - HexMap hexMap; - for (auto i = _s.rbegin(); i != _s.rend(); ++i) - hexMap[asNibbles(i->first)] = bytes(i->second.begin(), i->second.end()); - RLPStream s; - hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); - return sha3(s.out()); -} - -bytes rlp256(StringMap const& _s) -{ - // build patricia tree. - if (_s.empty()) - return rlp(""); - HexMap hexMap; - for (auto i = _s.rbegin(); i != _s.rend(); ++i) - hexMap[asNibbles(i->first)] = bytes(i->second.begin(), i->second.end()); - RLPStream s; - hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); - return s.out(); -} - -/*h256 orderedTrieRoot(std::vector const& _data) +h256 orderedTrieRoot(std::vector const& _data) { - StringMap m; + BytesMap m; unsigned j = 0; for (auto i: _data) - m[asString(rlp(j++))] = asString(i); + m[rlp(j++)] = i; return hash256(m); -}*/ - -h256 orderedTrieRoot(std::vector const& _data) -{ - MemoryDB db; - GenericTrieDB t(&db); - t.init(); - unsigned j = 0; - for (auto i: _data) - t.insert(rlp(j++), i.toBytes()); - return t.root(); } -h256 orderedTrieRoot(std::vector const& _data) +h256 orderedTrieRoot(std::vector const& _data) { - MemoryDB db; - GenericTrieDB t(&db); - t.init(); + BytesMap m; unsigned j = 0; for (auto i: _data) - t.insert(rlp(j++), i); - return t.root(); + m[rlp(j++)] = i.toBytes(); + return hash256(m); } } diff --git a/libdevcrypto/TrieHash.h b/libdevcrypto/TrieHash.h index 46f9b1efb..9649ef0c7 100644 --- a/libdevcrypto/TrieHash.h +++ b/libdevcrypto/TrieHash.h @@ -29,18 +29,16 @@ namespace dev bytes rlp256(BytesMap const& _s); h256 hash256(BytesMap const& _s); -bytes rlp256(StringMap const& _s); -h256 hash256(StringMap const& _s); -/*h256 orderedTrieRoot(std::vector const& _data); +h256 orderedTrieRoot(std::vector const& _data); template inline h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue) { - StringMap m; + BytesMap m; for (unsigned i = 0; i < _itemCount; ++i) - m[asString(_getKey(i))] = asString(_getValue(i)); + m[_getKey(i)] = _getValue(i); return hash256(m); -}*/ +} h256 orderedTrieRoot(std::vector const& _data); h256 orderedTrieRoot(std::vector const& _data); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 00a5108c4..0c324d70f 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -191,22 +191,12 @@ void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; -template h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue) -{ - MemoryDB db; - GenericTrieDB t(&db); - t.init(); - for (unsigned i = 0; i < _itemCount; ++i) - t.insert(_getKey(i), _getValue(i)); - return t.root(); -} - void BlockInfo::verifyInternals(bytesConstRef _block) const { RLP root(_block); auto txList = root[1]; - auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); }); + auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); if (transactionsRoot != expectedRoot) diff --git a/test/libdevcrypto/trie.cpp b/test/libdevcrypto/trie.cpp index 00bccd241..b32fd70e1 100644 --- a/test/libdevcrypto/trie.cpp +++ b/test/libdevcrypto/trie.cpp @@ -296,7 +296,6 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) h256 stringMapHash256(StringMap const& _s) { - //return hash256(_s); BytesMap bytesMap; for (auto const& _v: _s) bytesMap.insert(std::make_pair(bytes(_v.first.begin(), _v.first.end()), bytes(_v.second.begin(), _v.second.end()))); @@ -305,7 +304,6 @@ h256 stringMapHash256(StringMap const& _s) bytes stringMapRlp256(StringMap const& _s) { - //return rlp256(_s); BytesMap bytesMap; for (auto const& _v: _s) bytesMap.insert(std::make_pair(bytes(_v.first.begin(), _v.first.end()), bytes(_v.second.begin(), _v.second.end()))); @@ -407,7 +405,6 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) cout << d; cout << m; cout << d.root() << endl; - cout << hash256(s) << endl; cout << stringMapHash256(s) << endl; BOOST_REQUIRE(d.check(true)); From 6ec7a618c22545ca6bd0b8e76cc7ac5348cb8f12 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 19 May 2015 14:12:33 +0200 Subject: [PATCH 18/70] small changes --- mix/qml/Debugger.qml | 1 - mix/qml/WebCodeEditor.qml | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index c6283b60e..9decc91ae 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -4,7 +4,6 @@ import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import Qt.labs.settings 1.0 -import QtGraphicalEffects 1.0 import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index 32e62d584..babb200e8 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -155,14 +155,15 @@ Item { for (var k in secondLocations) { lineError = secondLocations[k].start.line + 1; - secondErrorDetail += secondLocations[k].contractName + " line " + lineError + ", "; + secondErrorDetail += secondLocations[k].contractName + " line " + lineError + " - "; displayErrorAnnotations(secondLocations[k], errorOrigin, "second"); } var detail = error.split('\n')[0]; var reg = detail.match(/:\d+:\d+:/g); if (reg !== null) detail = detail.replace(reg[0], ""); - detail += secondErrorDetail; + if (secondLocations.length > 0) + detail += secondErrorDetail; displayErrorAnnotations(firstLocation, detail, "first"); } From 1a334221eab18ed3a40de80196b0756a9848120f Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 19 May 2015 14:23:28 +0200 Subject: [PATCH 19/70] removed unused module --- mix/qml/Debugger.qml | 1 - mix/qml/StatesComboBox.qml | 1 - mix/qml/StatusPane.qml | 1 - 3 files changed, 3 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index c6283b60e..9decc91ae 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -4,7 +4,6 @@ import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import Qt.labs.settings 1.0 -import QtGraphicalEffects 1.0 import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." diff --git a/mix/qml/StatesComboBox.qml b/mix/qml/StatesComboBox.qml index 907580ee7..3d2b08eef 100644 --- a/mix/qml/StatesComboBox.qml +++ b/mix/qml/StatesComboBox.qml @@ -23,7 +23,6 @@ import QtQuick 2.0 import QtQuick.Controls 1.0 import QtQuick.Layouts 1.1 -import QtGraphicalEffects 1.0 import org.ethereum.qml.InverseMouseArea 1.0 Rectangle { diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 0c01caeb1..1c1453002 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -3,7 +3,6 @@ import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.InverseMouseArea 1.0 -import QtGraphicalEffects 1.0 import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." From 5f849c8eed8ce07fe5332df7349c3d2b6af07f5c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 19 May 2015 15:18:04 +0200 Subject: [PATCH 20/70] Fix DownloadView Race condition - There is a race condition with potential division by zero which is mostly observed when debugging AZ from gdb where there is a big gap between window refreshes due to breakpoints and such --- alethzero/DownloadView.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp index 009e2dc83..210649edb 100644 --- a/alethzero/DownloadView.cpp +++ b/alethzero/DownloadView.cpp @@ -52,7 +52,10 @@ void DownloadView::paintEvent(QPaintEvent*) QPointF pos(0, 0); auto bg = m_man->blocksGot(); - + unsigned subCount = m_man->subCount(); + if (subCount == 0) + return; + unsigned dh = 360 / subCount; for (unsigned i = bg.all().first, ei = bg.all().second; i < ei; ++i) { int s = -2; @@ -68,7 +71,6 @@ void DownloadView::paintEvent(QPaintEvent*) h++; }); } - unsigned dh = 360 / m_man->subCount(); if (s == -2) p.fillRect(QRectF(QPointF(pos) + QPointF(3 * area.width() / 8, 3 * area.height() / 8), area / 4), Qt::black); else if (s == -1) From f02962a3688e46f22fc8fd4228f2d5d26e8ee899 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 15:24:33 +0200 Subject: [PATCH 21/70] added constructor to solidiy abi --- libsolidity/InterfaceHandler.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 85026ac12..9817455b9 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -107,17 +107,25 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef) { string ret = "contract " + _contractDef.getName() + "{"; + + auto populateParameters = [](vector const& _paramNames, + vector const& _paramTypes) + { + string r = ""; + solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match"); + for (unsigned i = 0; i < _paramNames.size(); ++i) + r += (r.size() ? "," : "(") + _paramTypes[i] + " " + _paramNames[i]; + return r.size() ? r + ")" : "()"; + }; + if (_contractDef.getConstructor()) + { + auto externalFunction = FunctionType(*_contractDef.getConstructor()).externalFunctionType(); + solAssert(!!externalFunction, ""); + ret += "function " + _contractDef.getName() + + populateParameters(externalFunction->getParameterNames(), externalFunction->getParameterTypeNames()); + } for (auto const& it: _contractDef.getInterfaceFunctions()) { - auto populateParameters = [](vector const& _paramNames, - vector const& _paramTypes) - { - string r = ""; - solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match"); - for (unsigned i = 0; i < _paramNames.size(); ++i) - r += (r.size() ? "," : "(") + _paramTypes[i] + " " + _paramNames[i]; - return r.size() ? r + ")" : "()"; - }; ret += "function " + it.second->getDeclaration().getName() + populateParameters(it.second->getParameterNames(), it.second->getParameterTypeNames()) + (it.second->isConstant() ? "constant " : ""); From 2d377d95eacab568c62139c962b560ed7897f567 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 15:33:08 +0200 Subject: [PATCH 22/70] added ';' --- libsolidity/InterfaceHandler.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 9817455b9..9124d210f 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -121,8 +121,11 @@ unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition { auto externalFunction = FunctionType(*_contractDef.getConstructor()).externalFunctionType(); solAssert(!!externalFunction, ""); - ret += "function " + _contractDef.getName() + - populateParameters(externalFunction->getParameterNames(), externalFunction->getParameterTypeNames()); + ret += + "function " + + _contractDef.getName() + + populateParameters(externalFunction->getParameterNames(), externalFunction->getParameterTypeNames()) + + ";"; } for (auto const& it: _contractDef.getInterfaceFunctions()) { From cbdb46ea435c34485f178f7d9a77ee59a75d8db9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 15:56:56 +0200 Subject: [PATCH 23/70] Miner fix. Possible fix for VM (and remove gas from the interface). --- libethash-cl/ethash_cl_miner.cpp | 15 ++++++++------- libethcore/Ethash.cpp | 4 ++-- libethereum/KeyManager.cpp | 4 ++++ libevm/SmartVM.h | 6 +++++- libevm/VM.cpp | 14 +++++++++----- libevm/VM.h | 8 +++++--- libevm/VMFace.h | 9 +++------ 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 3891f2ef6..be17ba449 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -206,14 +206,15 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); // compute dag on CPU - { + try { m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag); - - // if this throws then it's because we probably need to subdivide the dag uploads for compatibility -// void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize); - // memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap. -// _fillDAG(dag_ptr); -// m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); + } + catch (...) + { + // didn't work. shitty driver. try allocating in CPU RAM and manually memcpying it. + void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, _dagSize); + memcpy(dag_ptr, _dag, _dagSize); + m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); } // create mining buffers diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 7609d8b6b..6276dd0a1 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -333,9 +333,9 @@ void Ethash::GPUMiner::workLoop() uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); } - catch (...) + catch (cl::Error const& _e) { - cwarn << "Error GPU mining. GPU memory fragmentation?"; + cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; } } diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp index 11b2cb2a6..cba6f4325 100644 --- a/libethereum/KeyManager.cpp +++ b/libethereum/KeyManager.cpp @@ -61,7 +61,11 @@ bool KeyManager::load(std::string const& _pass) if (version == 1) { for (auto const& i: s[1]) + { m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]); + cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3]; + } + for (auto const& i: s[2]) m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; diff --git a/libevm/SmartVM.h b/libevm/SmartVM.h index 29f464ecd..e21af23b0 100644 --- a/libevm/SmartVM.h +++ b/libevm/SmartVM.h @@ -31,12 +31,16 @@ namespace eth class SmartVM: public VMFace { public: - SmartVM(u256 _gas): VMFace(_gas) {} + SmartVM(u256 const& _gas): m_gas(_gas) {} virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + void reset(u256 const& _gas = 0) noexcept override { m_gas = _gas; } + u256 gas() const noexcept override { return (u256)m_gas; } + private: std::unique_ptr m_selectedVM; + bigint m_gas; }; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 853ac25f6..368d27389 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,9 +25,9 @@ using namespace std; using namespace dev; using namespace dev::eth; -void VM::reset(u256 _gas) noexcept +void VM::reset(u256 const& _gas) noexcept { - VMFace::reset(_gas); + m_gas = _gas; m_curPC = 0; m_jumpDests.clear(); } @@ -206,7 +206,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) BOOST_THROW_EXCEPTION(OutOfGas()); } - m_gas = (u256)((bigint)m_gas - runGas); + m_gas -= runGas; if (newTempSize > m_temp.size()) m_temp.resize((size_t)newTempSize); @@ -565,7 +565,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.push_back(m_temp.size()); break; case Instruction::GAS: - m_stack.push_back(m_gas); + m_stack.push_back((u256)m_gas); break; case Instruction::JUMPDEST: break; @@ -614,7 +614,11 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.pop_back(); if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) - m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); + { + u256 g(m_gas); + m_stack.push_back((u160)_ext.create(endowment, g, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); + m_gas = g; + } else m_stack.push_back(0); break; diff --git a/libevm/VM.h b/libevm/VM.h index 30007e0b3..668544f9d 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -52,8 +52,6 @@ inline u256 fromAddress(Address _a) class VM: public VMFace { public: - virtual void reset(u256 _gas = 0) noexcept override final; - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d > c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } } @@ -64,17 +62,21 @@ public: bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } + void reset(u256 const& _gas = 0) noexcept override; + u256 gas() const noexcept override { return (u256)m_gas; } + private: friend class VMFactory; /// Construct VM object. - explicit VM(u256 _gas): VMFace(_gas) {} + explicit VM(u256 _gas): m_gas(_gas) {} u256 m_curPC = 0; bytes m_temp; u256s m_stack; std::set m_jumpDests; std::function m_onFail; + bigint m_gas = 0; }; } diff --git a/libevm/VMFace.h b/libevm/VMFace.h index d2689d13e..92e6d4c4f 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -38,18 +38,15 @@ struct StackUnderflow: virtual VMException {}; class VMFace { public: - explicit VMFace(u256 _gas): m_gas(_gas) {} + VMFace() = default; virtual ~VMFace() = default; VMFace(VMFace const&) = delete; VMFace& operator=(VMFace const&) = delete; - virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } - u256 gas() const noexcept { return m_gas; } + virtual void reset(u256 const& _gas = 0) noexcept = 0; + virtual u256 gas() const noexcept = 0; virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; - -protected: - u256 m_gas = 0; }; } From bb7ca7a6b44ff776b86e42dc262f3b3293a6ba4f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 19 May 2015 16:46:00 +0200 Subject: [PATCH 24/70] handle output larger than 4069 bytes in test --- test/TestHelper.cpp | 9 +++++++-- .../StateTestsFiller/stMemoryStressTestFiller.json | 6 +++--- test/libevm/vm.cpp | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index aada83041..476d1ecf9 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -327,7 +327,8 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta void ImportTest::exportTest(bytes const& _output, State const& _statePost) { // export output - m_TestObject["out"] = toHex(_output, 2, HexPrefix::Add); + + m_TestObject["out"] = _output.size() > 4096 ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); // export logs m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); @@ -489,7 +490,11 @@ LogEntries importLog(json_spirit::mArray& _a) void checkOutput(bytes const& _output, json_spirit::mObject& _o) { int j = 0; - if (_o["out"].type() == json_spirit::array_type) + + if (_o["out"].get_str().find("#") == 0) + BOOST_CHECK((u256)_output.size() == toInt(_o["out"].get_str().substr(1))); + + else if (_o["out"].type() == json_spirit::array_type) for (auto const& d: _o["out"].get_array()) { BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); diff --git a/test/libethereum/StateTestsFiller/stMemoryStressTestFiller.json b/test/libethereum/StateTestsFiller/stMemoryStressTestFiller.json index 3893223eb..b5a531520 100644 --- a/test/libethereum/StateTestsFiller/stMemoryStressTestFiller.json +++ b/test/libethereum/StateTestsFiller/stMemoryStressTestFiller.json @@ -58,7 +58,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : "0", - "code" : "{ (RETURN 0 4294967297) } ", + "code" : "{ (RETURN 0 4294967295) } ", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -77,7 +77,7 @@ "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "data" : "" } - }, + }, "mload32bitBound_return2": { "env" : { @@ -98,7 +98,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : "0", - "code" : "{[ 0 ] 1 (RETURN 0 4294967296) } ", + "code" : "{[ 0 ] 1 (RETURN 0 4294967295) } ", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 10670bfe3..18153f2bf 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -393,7 +393,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } o["callcreates"] = fev.exportCallCreates(); - o["out"] = toHex(output, 2, HexPrefix::Add); + o["out"] = output.size() > 4096 ? "#" + toString(output.size()) : toHex(output, 2, HexPrefix::Add); o["gas"] = toCompactHex(gas, HexPrefix::Add, 1); o["logs"] = exportLog(fev.sub.logs); } From 465179e6f93b0f4dcdb71a4e7c6d4b17b5231915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 19 May 2015 17:44:07 +0200 Subject: [PATCH 25/70] Avoid forbidden function pointer cast. --- evmjit/include/evmjit/JIT.h | 4 ++-- evmjit/libevmjit/ExecutionEngine.cpp | 2 +- evmjit/libevmjit/JIT.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/evmjit/include/evmjit/JIT.h b/evmjit/include/evmjit/JIT.h index 446dd9e56..c9ddde705 100644 --- a/evmjit/include/evmjit/JIT.h +++ b/evmjit/include/evmjit/JIT.h @@ -28,8 +28,8 @@ public: private: friend class dev::eth::jit::ExecutionEngine; - static void* getCode(h256 _codeHash); - static void mapCode(h256 _codeHash, void* _funcAddr); + static uint64_t getCode(h256 _codeHash); + static void mapCode(h256 _codeHash, uint64_t _funcAddr); }; } diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 08ca403b5..e5abb36b3 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -183,7 +183,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); if (!CHECK(entryFuncPtr)) return ReturnCode::LLVMLinkError; - JIT::mapCode(_data->codeHash, (void*)entryFuncPtr); // FIXME: Remove cast + JIT::mapCode(_data->codeHash, (uint64_t)entryFuncPtr); // FIXME: Remove cast } listener->stateChanged(ExecState::Execution); diff --git a/evmjit/libevmjit/JIT.cpp b/evmjit/libevmjit/JIT.cpp index 9774c7396..8617fab6d 100644 --- a/evmjit/libevmjit/JIT.cpp +++ b/evmjit/libevmjit/JIT.cpp @@ -12,7 +12,7 @@ namespace class JITImpl: JIT { public: - std::unordered_map codeMap; + std::unordered_map codeMap; static JITImpl& instance() { @@ -28,16 +28,16 @@ bool JIT::isCodeReady(h256 _codeHash) return JITImpl::instance().codeMap.count(_codeHash) != 0; } -void* JIT::getCode(h256 _codeHash) +uint64_t JIT::getCode(h256 _codeHash) { auto& codeMap = JITImpl::instance().codeMap; auto it = codeMap.find(_codeHash); if (it != codeMap.end()) return it->second; - return nullptr; + return 0; } -void JIT::mapCode(h256 _codeHash, void* _funcAddr) +void JIT::mapCode(h256 _codeHash, uint64_t _funcAddr) { JITImpl::instance().codeMap.insert(std::make_pair(_codeHash, _funcAddr)); } From 9adde95145acc8f097c828dc362e8c0f22a090c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 19:38:17 +0200 Subject: [PATCH 26/70] SHA3, RIPEMD160 and SHA256 are now not cryptopp impls. --- libdevcrypto/AES.cpp | 32 +- libdevcrypto/AES.h | 5 +- libdevcrypto/Common.cpp | 1 + libdevcrypto/Hash.cpp | 440 ++++++++++++++++++++++ libdevcrypto/Hash.h | 38 ++ libdevcrypto/SHA3.cpp | 255 +++++++++---- libdevcrypto/SHA3.h | 37 +- libdevcrypto/picosha2.h | 360 ++++++++++++++++++ libethereum/Precompiled.cpp | 13 +- test/libdevcrypto/crypto.cpp | 14 +- test/libsolidity/SolidityEndToEndTest.cpp | 10 +- 11 files changed, 1075 insertions(+), 130 deletions(-) create mode 100644 libdevcrypto/Hash.cpp create mode 100644 libdevcrypto/Hash.h create mode 100644 libdevcrypto/picosha2.h diff --git a/libdevcrypto/AES.cpp b/libdevcrypto/AES.cpp index 56885ae36..e9edac0d3 100644 --- a/libdevcrypto/AES.cpp +++ b/libdevcrypto/AES.cpp @@ -19,9 +19,9 @@ * @date 2014 */ -#include "CryptoPP.h" #include "AES.h" - +#include +#include "CryptoPP.h" using namespace std; using namespace dev; using namespace dev::crypto; @@ -58,3 +58,31 @@ size_t Stream::streamOut(bytes&) return 0; } +bytes dev::aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) +{ + bytes pw = asBytes(_password); + + if (!_salt.size()) + _salt = &pw; + + bytes target(64); + CryptoPP::PKCS5_PBKDF2_HMAC().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds); + + try + { + CryptoPP::AES::Decryption aesDecryption(target.data(), 16); + auto cipher = _ivCipher.cropped(16); + auto iv = _ivCipher.cropped(0, 16); + CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data()); + std::string decrypted; + CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted)); + stfDecryptor.Put(cipher.data(), cipher.size()); + stfDecryptor.MessageEnd(); + return asBytes(decrypted); + } + catch (exception const& e) + { + cerr << e.what() << endl; + return bytes(); + } +} diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h index f0646eb85..32d1880dc 100644 --- a/libdevcrypto/AES.h +++ b/libdevcrypto/AES.h @@ -86,4 +86,7 @@ private: } } -} \ No newline at end of file + +bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); + +} diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index a5c176fe6..52be6ce3b 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -27,6 +27,7 @@ #include #include #include "SHA3.h" +#include "AES.h" #include "FileSystem.h" #include "CryptoPP.h" using namespace std; diff --git a/libdevcrypto/Hash.cpp b/libdevcrypto/Hash.cpp new file mode 100644 index 000000000..c6b917b90 --- /dev/null +++ b/libdevcrypto/Hash.cpp @@ -0,0 +1,440 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Hash.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Hash.h" +#include +#include +#include +#include "picosha2.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +h256 sha256(bytesConstRef _input) +{ + h256 ret; + picosha2::hash256(_input.begin(), _input.end(), ret.data(), ret.data() + 32); + return ret; +} + +namespace rmd160 +{ + +/********************************************************************\ + * + * FILE: rmd160.h + * FILE: rmd160.c + * + * CONTENTS: Header file for a sample C-implementation of the + * RIPEMD-160 hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * + \********************************************************************/ + +// Adapted into "header-only" format by Gav Wood. + +/* macro definitions */ + +#define RMDsize 160 + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ +(((uint32_t) *((strptr)+3) << 24) | \ +((uint32_t) *((strptr)+2) << 16) | \ +((uint32_t) *((strptr)+1) << 8) | \ +((uint32_t) *(strptr))) + +/* ROL(x, n) cyclically rotates x over n bits to the left */ +/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* the five basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) {\ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define GG(a, b, c, d, e, x, s) {\ +(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define HH(a, b, c, d, e, x, s) {\ +(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define II(a, b, c, d, e, x, s) {\ +(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define JJ(a, b, c, d, e, x, s) {\ +(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define FFF(a, b, c, d, e, x, s) {\ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define GGG(a, b, c, d, e, x, s) {\ +(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define HHH(a, b, c, d, e, x, s) {\ +(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define III(a, b, c, d, e, x, s) {\ +(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define JJJ(a, b, c, d, e, x, s) {\ +(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} + +void MDinit(uint32_t *MDbuf) +{ + MDbuf[0] = 0x67452301UL; + MDbuf[1] = 0xefcdab89UL; + MDbuf[2] = 0x98badcfeUL; + MDbuf[3] = 0x10325476UL; + MDbuf[4] = 0xc3d2e1f0UL; + + return; +} + +/********************************************************************/ + +void MDcompress(uint32_t *MDbuf, uint32_t *X) +{ + uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], + dd = MDbuf[3], ee = MDbuf[4]; + uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], + ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; + + return; +} + +void MDfinish(uint32_t *MDbuf, byte const *strptr, uint32_t lswlen, uint32_t mswlen) +{ + unsigned int i; /* counter */ + uint32_t X[16]; /* message words */ + + memset(X, 0, 16*sizeof(uint32_t)); + + /* put bytes from strptr into X */ + for (i=0; i<(lswlen&63); i++) { + /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ + X[i>>2] ^= (uint32_t) *strptr++ << (8 * (i&3)); + } + + /* append the bit m_n == 1 */ + X[(lswlen>>2)&15] ^= (uint32_t)1 << (8*(lswlen&3) + 7); + + if ((lswlen & 63) > 55) { + /* length goes to next block */ + MDcompress(MDbuf, X); + memset(X, 0, 16*sizeof(uint32_t)); + } + + /* append length in bits*/ + X[14] = lswlen << 3; + X[15] = (lswlen >> 29) | (mswlen << 3); + MDcompress(MDbuf, X); + + return; +} + +#undef ROL +#undef F +#undef G +#undef H +#undef I +#undef J +#undef FF +#undef GG +#undef HH +#undef II +#undef JJ +#undef FFF +#undef GGG +#undef HHH +#undef III +#undef JJJ + +} + +/* + * @returns RMD(_input) + */ +h160 ripemd160(bytesConstRef _input) +{ + h160 hashcode; + uint32_t buffer[RMDsize / 32]; // contains (A, B, C, D(, E)) + uint32_t current[16]; // current 16-word chunk + + // initialize + rmd160::MDinit(buffer); + byte const* message = _input.data(); + uint32_t remaining = _input.size(); // # of bytes not yet processed + + // process message in 16x 4-byte chunks + for (; remaining >= 64; remaining -= 64) + { + for (unsigned i = 0; i < 16; i++) + { + current[i] = BYTES_TO_DWORD(message); + message += 4; + } + rmd160::MDcompress(buffer, current); + } + // length mod 64 bytes left + + // finish: + rmd160::MDfinish(buffer, message, _input.size(), 0); + + for (unsigned i = 0; i < RMDsize / 8; i += 4) + { + hashcode[i] = buffer[i >> 2]; // implicit cast to byte + hashcode[i + 1] = (buffer[i >> 2] >> 8); //extracts the 8 least + hashcode[i + 2] = (buffer[i >> 2] >> 16); // significant bits. + hashcode[i + 3] = (buffer[i >> 2] >> 24); + } + + return hashcode; +} + +#undef BYTES_TO_DWORD +#undef RMDsize + +} diff --git a/libdevcrypto/Hash.h b/libdevcrypto/Hash.h new file mode 100644 index 000000000..7c5fcd67a --- /dev/null +++ b/libdevcrypto/Hash.h @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Hash.h + * @author Gav Wood + * @date 2014 + * + * The FixedHash fixed-size "hash" container type. + */ + +#pragma once + +#include +#include +#include +#include "SHA3.h" + +namespace dev +{ + +h256 sha256(bytesConstRef _input); + +h160 ripemd160(bytesConstRef _input); + +} diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index b7a47b745..250936db1 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -20,8 +20,12 @@ */ #include "SHA3.h" - +#include +#include +#include +#include #include +#include "picosha2.h" #include "CryptoPP.h" using namespace std; using namespace dev; @@ -32,98 +36,189 @@ namespace dev h256 EmptySHA3 = sha3(bytesConstRef()); h256 EmptyListSHA3 = sha3(rlpList()); -std::string sha3(std::string const& _input, bool _hex) +namespace keccak { - if (!_hex) - { - string ret(32, '\0'); - sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32)); - return ret; - } - - uint8_t buf[32]; - sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32)); - std::string ret(64, '\0'); - for (unsigned int i = 0; i < 32; i++) - sprintf((char*)(ret.data())+i*2, "%02x", buf[i]); - return ret; -} -void sha3(bytesConstRef _input, bytesRef _output) -{ - CryptoPP::SHA3_256 ctx; - ctx.Update((byte*)_input.data(), _input.size()); - assert(_output.size() >= 32); - ctx.Final(_output.data()); -} +/** libkeccak-tiny + * + * A single-file implementation of SHA-3 and SHAKE. + * + * Implementor: David Leon Gil + * License: CC0, attribution kindly requested. Blame taken too, + * but not liability. + */ -void ripemd160(bytesConstRef _input, bytesRef _output) -{ - CryptoPP::RIPEMD160 ctx; - ctx.Update((byte*)_input.data(), _input.size()); - assert(_output.size() >= 32); - ctx.Final(_output.data()); +#define decshake(bits) \ + int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); + +decshake(128) +decshake(256) +decsha3(224) +decsha3(256) +decsha3(384) +decsha3(512) + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } } -void sha256(bytesConstRef _input, bytesRef _output) -{ - CryptoPP::SHA256 ctx; - ctx.Update((byte*)_input.data(), _input.size()); - assert(_output.size() >= 32); - ctx.Final(_output.data()); +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; } -bytes sha3Bytes(bytesConstRef _input) -{ - bytes ret(32); - sha3(_input, &ret); - return ret; +/*** Helper macros to define SHA3 and SHAKE instances. ***/ +#define defshake(bits) \ + int shake##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ + } +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHAKE VOFs ***/ +defshake(128) +defshake(256) + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(224) +defsha3(256) +defsha3(384) +defsha3(512) + } h256 sha3(bytesConstRef _input) { + // FIXME: What with unaligned memory? h256 ret; - sha3(_input, bytesRef(&ret[0], 32)); + keccak::sha3_256(ret.data(), 32, _input.data(), _input.size()); +// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); return ret; } - -void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) -{ - CryptoPP::SHA3_256 ctx; - assert(_secret.size() > 0); - ctx.Update((byte*)_secret.data(), _secret.size()); - ctx.Update((byte*)_plain.data(), _plain.size()); - assert(_output.size() >= 32); - ctx.Final(_output.data()); -} - -bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) -{ - bytes pw = asBytes(_password); - - if (!_salt.size()) - _salt = &pw; - - bytes target(64); - CryptoPP::PKCS5_PBKDF2_HMAC().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds); - - try - { - CryptoPP::AES::Decryption aesDecryption(target.data(), 16); - auto cipher = _ivCipher.cropped(16); - auto iv = _ivCipher.cropped(0, 16); - CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data()); - std::string decrypted; - CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted)); - stfDecryptor.Put(cipher.data(), cipher.size()); - stfDecryptor.MessageEnd(); - return asBytes(decrypted); - } - catch (exception const& e) - { - cerr << e.what() << endl; - return bytes(); - } -} } diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index 66b8efe11..c3ef524fe 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -32,46 +32,29 @@ namespace dev // SHA-3 convenience routines. -/// Calculate SHA3-256 hash of the given input and load it into the given output. -void sha3(bytesConstRef _input, bytesRef _output); - -/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. -std::string sha3(std::string const& _input, bool _isNibbles); - -/// Calculate SHA3-256 hash of the given input, returning as a byte array. -bytes sha3Bytes(bytesConstRef _input); - -/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array. -inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); } - -/// Calculate SHA3-256 hash of the given input, returning as a byte array. -inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); } - /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. h256 sha3(bytesConstRef _input); +/// Calculate SHA3-256 hash of the given input and load it into the given output. +inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); } + /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); } +inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } - -/// Calculate SHA3-256 MAC -void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output); /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } -extern h256 EmptySHA3; - -extern h256 EmptyListSHA3; - -// Other crypto convenience routines +/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. +inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } -bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); +/// Calculate SHA3-256 MAC +inline void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { sha3(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); } -void sha256(bytesConstRef _input, bytesRef _output); +extern h256 EmptySHA3; -void ripemd160(bytesConstRef _input, bytesRef _output); +extern h256 EmptyListSHA3; } diff --git a/libdevcrypto/picosha2.h b/libdevcrypto/picosha2.h new file mode 100644 index 000000000..44b6bee59 --- /dev/null +++ b/libdevcrypto/picosha2.h @@ -0,0 +1,360 @@ +/* +The MIT License (MIT) + +Copyright (C) 2014 okdshin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef PICOSHA2_H +#define PICOSHA2_H +//picosha2:20140213 +#include +#include +#include +#include +#include +#include +#include + +namespace picosha2 +{ + +namespace detail +{ + +inline uint8_t mask_8bit(uint8_t x){ + return x&0xff; +} + +inline uint32_t mask_32bit(uint32_t x){ + return x&0xffffffff; +} + +static const uint32_t add_constant[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static const uint32_t initial_message_digest[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z){ + return (x&y)^((~x)&z); +} + +inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z){ + return (x&y)^(x&z)^(y&z); +} + +inline uint32_t rotr(uint32_t x, std::size_t n){ + assert(n < 32); + return mask_32bit((x>>n)|(x<<(32-n))); +} + +inline uint32_t bsig0(uint32_t x){ + return rotr(x, 2)^rotr(x, 13)^rotr(x, 22); +} + +inline uint32_t bsig1(uint32_t x){ + return rotr(x, 6)^rotr(x, 11)^rotr(x, 25); +} + +inline uint32_t shr(uint32_t x, std::size_t n){ + assert(n < 32); + return x >> n; +} + +inline uint32_t ssig0(uint32_t x){ + return rotr(x, 7)^rotr(x, 18)^shr(x, 3); +} + +inline uint32_t ssig1(uint32_t x){ + return rotr(x, 17)^rotr(x, 19)^shr(x, 10); +} + +template +void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last){ + (void)last; // FIXME: check this is valid + uint32_t w[64]; + std::fill(w, w+64, 0); + for(std::size_t i = 0; i < 16; ++i){ + w[i] = (static_cast(mask_8bit(*(first+i*4)))<<24) + |(static_cast(mask_8bit(*(first+i*4+1)))<<16) + |(static_cast(mask_8bit(*(first+i*4+2)))<<8) + |(static_cast(mask_8bit(*(first+i*4+3)))); + } + for(std::size_t i = 16; i < 64; ++i){ + w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]); + } + + uint32_t a = *message_digest; + uint32_t b = *(message_digest+1); + uint32_t c = *(message_digest+2); + uint32_t d = *(message_digest+3); + uint32_t e = *(message_digest+4); + uint32_t f = *(message_digest+5); + uint32_t g = *(message_digest+6); + uint32_t h = *(message_digest+7); + + for(std::size_t i = 0; i < 64; ++i){ + uint32_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i]; + uint32_t temp2 = bsig0(a)+maj(a,b,c); + h = g; + g = f; + f = e; + e = mask_32bit(d+temp1); + d = c; + c = b; + b = a; + a = mask_32bit(temp1+temp2); + } + *message_digest += a; + *(message_digest+1) += b; + *(message_digest+2) += c; + *(message_digest+3) += d; + *(message_digest+4) += e; + *(message_digest+5) += f; + *(message_digest+6) += g; + *(message_digest+7) += h; + for(std::size_t i = 0; i < 8; ++i){ + *(message_digest+i) = mask_32bit(*(message_digest+i)); + } +} + +}//namespace detail + +template +void output_hex(InIter first, InIter last, std::ostream& os){ + os.setf(std::ios::hex, std::ios::basefield); + while(first != last){ + os.width(2); + os.fill('0'); + os << static_cast(*first); + ++first; + } + os.setf(std::ios::dec, std::ios::basefield); +} + +template +void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str){ + std::ostringstream oss; + output_hex(first, last, oss); + hex_str.assign(oss.str()); +} + +template +void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str){ + bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str); +} + +template +std::string bytes_to_hex_string(InIter first, InIter last){ + std::string hex_str; + bytes_to_hex_string(first, last, hex_str); + return hex_str; +} + +template +std::string bytes_to_hex_string(const InContainer& bytes){ + std::string hex_str; + bytes_to_hex_string(bytes, hex_str); + return hex_str; +} + +class hash256_one_by_one { +public: + hash256_one_by_one(){ + init(); + } + + void init(){ + buffer_.clear(); + std::fill(data_length_digits_, data_length_digits_+4, 0); + std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_); + } + + template + void process(RaIter first, RaIter last){ + add_to_data_length(std::distance(first, last)); + std::copy(first, last, std::back_inserter(buffer_)); + std::size_t i = 0; + for(;i+64 <= buffer_.size(); i+=64){ + detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64); + } + buffer_.erase(buffer_.begin(), buffer_.begin()+i); + } + + void finish(){ + uint8_t temp[64]; + std::fill(temp, temp+64, 0); + std::size_t remains = buffer_.size(); + std::copy(buffer_.begin(), buffer_.end(), temp); + temp[remains] = 0x80; + + if(remains > 55){ + std::fill(temp+remains+1, temp+64, 0); + detail::hash256_block(h_, temp, temp+64); + std::fill(temp, temp+64-4, 0); + } + else { + std::fill(temp+remains+1, temp+64-4, 0); + } + + write_data_bit_length(&(temp[56])); + detail::hash256_block(h_, temp, temp+64); + } + + template + void get_hash_bytes(OutIter first, OutIter last)const{ + for(const uint32_t* iter = h_; iter != h_+8; ++iter){ + for(std::size_t i = 0; i < 4 && first != last; ++i){ + *(first++) = detail::mask_8bit(static_cast((*iter >> (24-8*i)))); + } + } + } + +private: + void add_to_data_length(uint32_t n) { + uint32_t carry = 0; + data_length_digits_[0] += n; + for(std::size_t i = 0; i < 4; ++i) { + data_length_digits_[i] += carry; + if(data_length_digits_[i] >= 65536u) { + data_length_digits_[i] -= 65536u; + carry = 1; + } + else { + break; + } + } + } + void write_data_bit_length(uint8_t* begin) { + uint32_t data_bit_length_digits[4]; + std::copy( + data_length_digits_, data_length_digits_+4, + data_bit_length_digits + ); + + // convert byte length to bit length (multiply 8 or shift 3 times left) + uint32_t carry = 0; + for(std::size_t i = 0; i < 4; ++i) { + uint32_t before_val = data_bit_length_digits[i]; + data_bit_length_digits[i] <<= 3; + data_bit_length_digits[i] |= carry; + data_bit_length_digits[i] &= 65535u; + carry = (before_val >> (16-3)) & 65535u; + } + + // write data_bit_length + for(int i = 3; i >= 0; --i) { + (*begin++) = static_cast(data_bit_length_digits[i] >> 8); + (*begin++) = static_cast(data_bit_length_digits[i]); + } + } + std::vector buffer_; + uint32_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer) + uint32_t h_[8]; +}; + +inline void get_hash_hex_string(const hash256_one_by_one& hasher, std::string& hex_str){ + uint8_t hash[32]; + hasher.get_hash_bytes(hash, hash+32); + return bytes_to_hex_string(hash, hash+32, hex_str); +} + +inline std::string get_hash_hex_string(const hash256_one_by_one& hasher){ + std::string hex_str; + get_hash_hex_string(hasher, hex_str); + return hex_str; +} + +template +void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2){ + hash256_one_by_one hasher; + //hasher.init(); + hasher.process(first, last); + hasher.finish(); + hasher.get_hash_bytes(first2, last2); +} + +template +void hash256(RaIter first, RaIter last, OutContainer& dst){ + hash256(first, last, dst.begin(), dst.end()); +} + +template +void hash256(const RaContainer& src, OutIter first, OutIter last){ + hash256(src.begin(), src.end(), first, last); +} + +template +void hash256(const RaContainer& src, OutContainer& dst){ + hash256(src.begin(), src.end(), dst.begin(), dst.end()); +} + + +template +void hash256_hex_string(RaIter first, RaIter last, std::string& hex_str){ + uint8_t hashed[32]; + hash256(first, last, hashed, hashed+32); + std::ostringstream oss; + output_hex(hashed, hashed+32, oss); + hex_str.assign(oss.str()); +} + +template +std::string hash256_hex_string(RaIter first, RaIter last){ + std::string hex_str; + hash256_hex_string(first, last, hex_str); + return hex_str; +} + +inline void hash256_hex_string(const std::string& src, std::string& hex_str){ + hash256_hex_string(src.begin(), src.end(), hex_str); +} + +template +void hash256_hex_string(const RaContainer& src, std::string& hex_str){ + hash256_hex_string(src.begin(), src.end(), hex_str); +} + +template +std::string hash256_hex_string(const RaContainer& src){ + return hash256_hex_string(src.begin(), src.end()); +} + +}//namespace picosha2 + +#endif //PICOSHA2_H diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index cdcb4a46a..9373697e1 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -21,7 +21,9 @@ #include "Precompiled.h" +#include #include +#include #include #include #include @@ -61,19 +63,12 @@ static bytes ecrecoverCode(bytesConstRef _in) static bytes sha256Code(bytesConstRef _in) { - bytes ret(32); - sha256(_in, &ret); - return ret; + return sha256(_in).asBytes(); } static bytes ripemd160Code(bytesConstRef _in) { - bytes ret(32); - ripemd160(_in, &ret); - // leaves the 20-byte hash left-aligned. we want it right-aligned: - memmove(ret.data() + 12, ret.data(), 20); - memset(ret.data(), 0, 12); - return ret; + return h256(ripemd160(_in), h256::AlignRight).asBytes(); } static bytes identityCode(bytesConstRef _in) diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 88ff98965..3381c45da 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -45,13 +45,19 @@ static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1()); static CryptoPP::DL_GroupParameters_EC s_params(s_curveOID); static CryptoPP::DL_GroupParameters_EC::EllipticCurve s_curve(s_params.GetCurve()); -BOOST_AUTO_TEST_CASE(emptySHA3Types) +BOOST_AUTO_TEST_CASE(sha3general) { - h256 emptyListSHA3(fromHex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); - BOOST_REQUIRE_EQUAL(emptyListSHA3, EmptyListSHA3); + BOOST_REQUIRE_EQUAL(sha3(""), h256("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); + BOOST_REQUIRE_EQUAL(sha3("hello"), h256("1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8")); +} +BOOST_AUTO_TEST_CASE(emptySHA3Types) +{ h256 emptySHA3(fromHex("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); BOOST_REQUIRE_EQUAL(emptySHA3, EmptySHA3); + + h256 emptyListSHA3(fromHex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); + BOOST_REQUIRE_EQUAL(emptyListSHA3, EmptyListSHA3); } BOOST_AUTO_TEST_CASE(cryptopp_patch) @@ -805,7 +811,7 @@ int cryptoTest() std::string hmsg = sha3(t.rlp(false), false); cout << "SHA256(RLP(TX w/o SIG)): 0x" << toHex(hmsg) << endl; - bytes privkey = sha3Bytes("123"); + bytes privkey = sha3("123").asBytes(); { bytes pubkey(65); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 6713382fa..aa51a674d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include using namespace std; @@ -1501,9 +1501,7 @@ BOOST_AUTO_TEST_CASE(sha256) compileAndRun(sourceCode); auto f = [&](u256 const& _input) -> u256 { - h256 ret; - dev::sha256(dev::ref(toBigEndian(_input)), bytesRef(&ret[0], 32)); - return ret; + return dev::sha256(dev::ref(toBigEndian(_input))); }; testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(5)); @@ -1520,9 +1518,7 @@ BOOST_AUTO_TEST_CASE(ripemd) compileAndRun(sourceCode); auto f = [&](u256 const& _input) -> u256 { - h256 ret; - dev::ripemd160(dev::ref(toBigEndian(_input)), bytesRef(&ret[0], 32)); - return u256(ret); + return h256(dev::ripemd160(h256(_input).ref()), h256::AlignLeft); // This should be aligned right. i guess it's fixed elsewhere? }; testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(5)); From 05ea9941c9b468222026ad9923964456ce195496 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 19:51:38 +0200 Subject: [PATCH 27/70] Move non-cryptopp dependent stuff into devcore. --- abi/main.cpp | 2 +- alethzero/DappLoader.cpp | 2 +- alethzero/MainWin.cpp | 2 +- alethzero/NatspecHandler.cpp | 2 +- eth/main.cpp | 2 +- ethminer/MinerAux.h | 4 ++-- ethminer/main.cpp | 2 +- evmjit/libevmjit-cpp/Env.cpp | 2 +- evmjit/libevmjit-cpp/JitVM.cpp | 2 +- exp/main.cpp | 4 ++-- {libdevcrypto => libdevcore}/FileSystem.cpp | 4 ++-- {libdevcrypto => libdevcore}/FileSystem.h | 0 {libdevcrypto => libdevcore}/Hash.cpp | 0 {libdevcrypto => libdevcore}/Hash.h | 0 {libdevcrypto => libdevcore}/MemoryDB.cpp | 0 {libdevcrypto => libdevcore}/MemoryDB.h | 0 {libdevcrypto => libdevcore}/OverlayDB.cpp | 0 {libdevcrypto => libdevcore}/OverlayDB.h | 0 {libdevcrypto => libdevcore}/SHA3.cpp | 1 - {libdevcrypto => libdevcore}/SHA3.h | 0 {libdevcrypto => libdevcore}/TrieCommon.cpp | 0 {libdevcrypto => libdevcore}/TrieCommon.h | 0 {libdevcrypto => libdevcore}/TrieDB.cpp | 0 {libdevcrypto => libdevcore}/TrieDB.h | 2 +- {libdevcrypto => libdevcore}/TrieHash.cpp | 6 +++--- {libdevcrypto => libdevcore}/TrieHash.h | 0 {libdevcrypto => libdevcore}/picosha2.h | 0 libdevcrypto/Common.cpp | 4 ++-- libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/ECDHE.cpp | 4 ++-- libdevcrypto/SecretStore.cpp | 4 ++-- libdevcrypto/SecretStore.h | 2 +- libethcore/ABI.h | 2 +- libethcore/BlockInfo.cpp | 4 ++-- libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 2 +- libethcore/EthashAux.cpp | 4 ++-- libethcore/ICAP.cpp | 2 +- libethereum/Account.h | 4 ++-- libethereum/BlockChain.cpp | 2 +- libethereum/CachedAddressState.cpp | 2 +- libethereum/CanonBlockChain.cpp | 2 +- libethereum/Defaults.cpp | 2 +- libethereum/KeyManager.h | 2 +- libethereum/LogFilter.cpp | 2 +- libethereum/Precompiled.cpp | 4 ++-- libethereum/State.cpp | 2 +- libethereum/State.h | 2 +- libethereum/Transaction.h | 2 +- libethereum/Utility.cpp | 2 +- libevm/ExtVMFace.h | 2 +- libevm/SmartVM.cpp | 2 +- libevm/VM.h | 2 +- libevmasm/CommonSubexpressionEliminator.cpp | 2 +- libevmasm/KnownState.cpp | 2 +- libp2p/Host.cpp | 2 +- libp2p/UDP.h | 2 +- libsolidity/AST.cpp | 2 +- libsolidity/CompilerStack.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 2 +- libsolidity/Types.cpp | 2 +- libtestutils/Common.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libwhisper/Common.cpp | 2 +- libwhisper/Interface.h | 2 +- libwhisper/Message.h | 2 +- libwhisper/WhisperHost.h | 2 +- libwhisper/WhisperPeer.h | 2 +- mix/FileIo.cpp | 2 +- mix/QFunctionDefinition.cpp | 2 +- neth/main.cpp | 2 +- rlp/main.cpp | 2 +- test/deprecated/main.cpp | 2 +- test/libdevcrypto/MemTrie.cpp | 4 ++-- test/libdevcrypto/crypto.cpp | 2 +- test/libdevcrypto/hexPrefix.cpp | 2 +- test/libdevcrypto/trie.cpp | 4 ++-- test/libethereum/blockchain.cpp | 2 +- test/libp2p/rlpx.cpp | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/SolidityNameAndTypeResolution.cpp | 2 +- third/MainWin.cpp | 2 +- 82 files changed, 82 insertions(+), 83 deletions(-) rename {libdevcrypto => libdevcore}/FileSystem.cpp (97%) rename {libdevcrypto => libdevcore}/FileSystem.h (100%) rename {libdevcrypto => libdevcore}/Hash.cpp (100%) rename {libdevcrypto => libdevcore}/Hash.h (100%) rename {libdevcrypto => libdevcore}/MemoryDB.cpp (100%) rename {libdevcrypto => libdevcore}/MemoryDB.h (100%) rename {libdevcrypto => libdevcore}/OverlayDB.cpp (100%) rename {libdevcrypto => libdevcore}/OverlayDB.h (100%) rename {libdevcrypto => libdevcore}/SHA3.cpp (99%) rename {libdevcrypto => libdevcore}/SHA3.h (100%) rename {libdevcrypto => libdevcore}/TrieCommon.cpp (100%) rename {libdevcrypto => libdevcore}/TrieCommon.h (100%) rename {libdevcrypto => libdevcore}/TrieDB.cpp (100%) rename {libdevcrypto => libdevcore}/TrieDB.h (99%) rename {libdevcrypto => libdevcore}/TrieHash.cpp (97%) rename {libdevcrypto => libdevcore}/TrieHash.h (100%) rename {libdevcrypto => libdevcore}/picosha2.h (100%) diff --git a/abi/main.cpp b/abi/main.cpp index 27c5eea1b..df7fa8811 100644 --- a/abi/main.cpp +++ b/abi/main.cpp @@ -26,7 +26,7 @@ #include "../test/JsonSpiritHeaders.h" #include #include -#include +#include #include using namespace std; using namespace dev; diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index a91beb2f7..b2249ae5b 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 9486f9f01..b59e9ce1f 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -44,7 +44,7 @@ #include #include #endif -#include +#include #include #include #include diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index a7cad6853..d00abc44f 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include using namespace dev; diff --git a/eth/main.cpp b/eth/main.cpp index 1cf918346..33d049843 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 040bd945c..8e480a3ff 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -31,11 +31,11 @@ #include #include -#include +#include #include #include #include -#include +#include #include #include #include diff --git a/ethminer/main.cpp b/ethminer/main.cpp index 5b82db471..4deba38d1 100644 --- a/ethminer/main.cpp +++ b/ethminer/main.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "MinerAux.h" using namespace std; using namespace dev; diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index a5a60f48c..d1f239f9f 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -1,6 +1,6 @@ #pragma GCC diagnostic ignored "-Wconversion" -#include +#include #include #include #include diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 7acbec5c1..6efd4c31a 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -4,7 +4,7 @@ #include "JitVM.h" #include -#include +#include #include #include #include diff --git a/exp/main.cpp b/exp/main.cpp index 138ae76a4..d31306496 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -41,12 +41,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include #include #include #include diff --git a/libdevcrypto/FileSystem.cpp b/libdevcore/FileSystem.cpp similarity index 97% rename from libdevcrypto/FileSystem.cpp rename to libdevcore/FileSystem.cpp index adf3a2946..dfda891f5 100644 --- a/libdevcrypto/FileSystem.cpp +++ b/libdevcore/FileSystem.cpp @@ -22,8 +22,8 @@ */ #include "FileSystem.h" -#include -#include +#include "Common.h" +#include "Log.h" #if defined(_WIN32) #include diff --git a/libdevcrypto/FileSystem.h b/libdevcore/FileSystem.h similarity index 100% rename from libdevcrypto/FileSystem.h rename to libdevcore/FileSystem.h diff --git a/libdevcrypto/Hash.cpp b/libdevcore/Hash.cpp similarity index 100% rename from libdevcrypto/Hash.cpp rename to libdevcore/Hash.cpp diff --git a/libdevcrypto/Hash.h b/libdevcore/Hash.h similarity index 100% rename from libdevcrypto/Hash.h rename to libdevcore/Hash.h diff --git a/libdevcrypto/MemoryDB.cpp b/libdevcore/MemoryDB.cpp similarity index 100% rename from libdevcrypto/MemoryDB.cpp rename to libdevcore/MemoryDB.cpp diff --git a/libdevcrypto/MemoryDB.h b/libdevcore/MemoryDB.h similarity index 100% rename from libdevcrypto/MemoryDB.h rename to libdevcore/MemoryDB.h diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcore/OverlayDB.cpp similarity index 100% rename from libdevcrypto/OverlayDB.cpp rename to libdevcore/OverlayDB.cpp diff --git a/libdevcrypto/OverlayDB.h b/libdevcore/OverlayDB.h similarity index 100% rename from libdevcrypto/OverlayDB.h rename to libdevcore/OverlayDB.h diff --git a/libdevcrypto/SHA3.cpp b/libdevcore/SHA3.cpp similarity index 99% rename from libdevcrypto/SHA3.cpp rename to libdevcore/SHA3.cpp index 250936db1..880f23d6e 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcore/SHA3.cpp @@ -26,7 +26,6 @@ #include #include #include "picosha2.h" -#include "CryptoPP.h" using namespace std; using namespace dev; diff --git a/libdevcrypto/SHA3.h b/libdevcore/SHA3.h similarity index 100% rename from libdevcrypto/SHA3.h rename to libdevcore/SHA3.h diff --git a/libdevcrypto/TrieCommon.cpp b/libdevcore/TrieCommon.cpp similarity index 100% rename from libdevcrypto/TrieCommon.cpp rename to libdevcore/TrieCommon.cpp diff --git a/libdevcrypto/TrieCommon.h b/libdevcore/TrieCommon.h similarity index 100% rename from libdevcrypto/TrieCommon.h rename to libdevcore/TrieCommon.h diff --git a/libdevcrypto/TrieDB.cpp b/libdevcore/TrieDB.cpp similarity index 100% rename from libdevcrypto/TrieDB.cpp rename to libdevcore/TrieDB.cpp diff --git a/libdevcrypto/TrieDB.h b/libdevcore/TrieDB.h similarity index 99% rename from libdevcrypto/TrieDB.h rename to libdevcore/TrieDB.h index cf85148d2..13a520311 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "MemoryDB.h" #include "OverlayDB.h" #include "TrieCommon.h" diff --git a/libdevcrypto/TrieHash.cpp b/libdevcore/TrieHash.cpp similarity index 97% rename from libdevcrypto/TrieHash.cpp rename to libdevcore/TrieHash.cpp index 0b02ce77f..ec0a92f90 100644 --- a/libdevcrypto/TrieHash.cpp +++ b/libdevcore/TrieHash.cpp @@ -20,9 +20,9 @@ */ #include "TrieHash.h" -#include -#include // @TODO replace ASAP! -#include +#include +#include // @TODO replace ASAP! +#include #include using namespace std; using namespace dev; diff --git a/libdevcrypto/TrieHash.h b/libdevcore/TrieHash.h similarity index 100% rename from libdevcrypto/TrieHash.h rename to libdevcore/TrieHash.h diff --git a/libdevcrypto/picosha2.h b/libdevcore/picosha2.h similarity index 100% rename from libdevcrypto/picosha2.h rename to libdevcore/picosha2.h diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 52be6ce3b..87e258573 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -26,9 +26,9 @@ #include #include #include -#include "SHA3.h" +#include +#include #include "AES.h" -#include "FileSystem.h" #include "CryptoPP.h" using namespace std; using namespace dev; diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 4991e3713..ca8a2e6b5 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -49,7 +49,7 @@ #include #pragma warning(pop) #pragma GCC diagnostic pop -#include "SHA3.h" +#include #include "Common.h" namespace dev diff --git a/libdevcrypto/ECDHE.cpp b/libdevcrypto/ECDHE.cpp index a00a92872..a5aaf3984 100644 --- a/libdevcrypto/ECDHE.cpp +++ b/libdevcrypto/ECDHE.cpp @@ -19,9 +19,9 @@ * @date 2014 */ -#include "SHA3.h" -#include "CryptoPP.h" #include "ECDHE.h" +#include +#include "CryptoPP.h" using namespace std; using namespace dev; diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 9be0b89e8..0416aa9f4 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -25,9 +25,9 @@ #include #include #include +#include +#include #include -#include "SHA3.h" -#include "FileSystem.h" using namespace std; using namespace dev; namespace js = json_spirit; diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 1fb6adf4a..18c290c1f 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -24,8 +24,8 @@ #include #include #include +#include #include "Common.h" -#include "FileSystem.h" namespace dev { diff --git a/libethcore/ABI.h b/libethcore/ABI.h index 7fca09c9a..09aca6754 100644 --- a/libethcore/ABI.h +++ b/libethcore/ABI.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace dev { diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 00a5108c4..22e171e31 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include #include #include #include "EthashAux.h" diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index c74aeba5e..56db647f3 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "Exceptions.h" #include "ProofOfWork.h" using namespace std; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6276dd0a1..1f16166f0 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #if ETH_ETHASHCL || !ETH_TRUE diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index eccb986a7..38425aca2 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -31,8 +31,8 @@ #include #include #include -#include -#include +#include +#include #include #include "BlockInfo.h" #include "Exceptions.h" diff --git a/libethcore/ICAP.cpp b/libethcore/ICAP.cpp index 6fce19a62..158c297f8 100644 --- a/libethcore/ICAP.cpp +++ b/libethcore/ICAP.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "Exceptions.h" #include "ABI.h" using namespace std; diff --git a/libethereum/Account.h b/libethereum/Account.h index 660dc0a4c..87fc82b6c 100644 --- a/libethereum/Account.h +++ b/libethereum/Account.h @@ -23,8 +23,8 @@ #include #include -#include -#include +#include +#include namespace dev { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 73747b25b..c46127303 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libethereum/CachedAddressState.cpp b/libethereum/CachedAddressState.cpp index a25017793..7c2f0a80c 100644 --- a/libethereum/CachedAddressState.cpp +++ b/libethereum/CachedAddressState.cpp @@ -22,7 +22,7 @@ #include "CachedAddressState.h" #include -#include +#include #include "Account.h" using namespace std; using namespace dev; diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index f1de7292b..5dd7dc2ce 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libethereum/Defaults.cpp b/libethereum/Defaults.cpp index febe53d84..b839bbb5c 100644 --- a/libethereum/Defaults.cpp +++ b/libethereum/Defaults.cpp @@ -21,7 +21,7 @@ #include "Defaults.h" -#include +#include using namespace std; using namespace dev; using namespace dev::eth; diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index 38e8d8853..bb537e1f1 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace dev { diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp index ab9848d59..21ba9d3ef 100644 --- a/libethereum/LogFilter.cpp +++ b/libethereum/LogFilter.cpp @@ -21,7 +21,7 @@ #include "LogFilter.h" -#include +#include #include "State.h" using namespace std; using namespace dev; diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index 9373697e1..0e80949fe 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -22,8 +22,8 @@ #include "Precompiled.h" #include -#include -#include +#include +#include #include #include #include diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 3bf7aaff7..d302e7381 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libethereum/State.h b/libethereum/State.h index d9fc9d2b5..971c2220a 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 78852b7b8..09d6cd54c 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -22,7 +22,7 @@ #pragma once #include -#include +#include #include #include namespace dev diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index 7b0a961b2..adfea4a51 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include using namespace std; using namespace dev; using namespace dev::eth; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 48fbd0b01..8ebfd8fa5 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp index 4f759a745..89397987e 100644 --- a/libevm/SmartVM.cpp +++ b/libevm/SmartVM.cpp @@ -21,7 +21,7 @@ #include "SmartVM.h" #include #include -#include +#include #include #include #include "VMFactory.h" diff --git a/libevm/VM.h b/libevm/VM.h index 668544f9d..181fcdc2e 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include "VMFace.h" diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 9f6f9dd63..b2fa73116 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 0aac9cedb..895778ed1 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -23,7 +23,7 @@ #include "KnownState.h" #include -#include +#include #include using namespace std; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index e2599c1d5..998579a90 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "Session.h" #include "Common.h" #include "Capability.h" diff --git a/libp2p/UDP.h b/libp2p/UDP.h index b09d556e7..a455b5057 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include "Common.h" diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 9842901e7..14884254e 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include using namespace std; diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index b3fedc45d..bffa4158f 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -31,7 +31,7 @@ #include #include -#include +#include using namespace std; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 838ee264e..2e513b7fc 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index d1f51decf..7577b83a1 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/libtestutils/Common.cpp b/libtestutils/Common.cpp index 5767be32c..cff21d464 100644 --- a/libtestutils/Common.cpp +++ b/libtestutils/Common.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "Common.h" using namespace std; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 5235b0c4f..44f7f521c 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include "WebThreeStubServer.h" using namespace std; diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index c29ac6bf6..dd9172c70 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -21,7 +21,7 @@ #include "Common.h" -#include +#include #include "Message.h" using namespace std; using namespace dev; diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index db595e21e..8b84193aa 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -29,7 +29,7 @@ #include #include -#include +#include #include "Common.h" #include "Message.h" diff --git a/libwhisper/Message.h b/libwhisper/Message.h index bd73df268..893602190 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "Common.h" namespace dev diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index ebbbcf8ed..cd427da35 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "Common.h" #include "WhisperPeer.h" #include "Interface.h" diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index 8542e987d..ab9c8222a 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -29,7 +29,7 @@ #include #include -#include +#include #include "Common.h" #include "Message.h" diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 22538194c..cf8300677 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "FileIo.h" using namespace dev; diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index 13dbd4821..e6764d712 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -20,7 +20,7 @@ */ #include -#include +#include #include #include "QVariableDeclaration.h" #include "QFunctionDefinition.h" diff --git a/neth/main.cpp b/neth/main.cpp index 7ce64cba5..a6e661d2e 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/rlp/main.cpp b/rlp/main.cpp index 5f2f7f358..3924f9c44 100644 --- a/rlp/main.cpp +++ b/rlp/main.cpp @@ -25,7 +25,7 @@ #include "../test/JsonSpiritHeaders.h" #include #include -#include +#include using namespace std; using namespace dev; namespace js = json_spirit; diff --git a/test/deprecated/main.cpp b/test/deprecated/main.cpp index 6ec8885b3..6cb098228 100644 --- a/test/deprecated/main.cpp +++ b/test/deprecated/main.cpp @@ -20,7 +20,7 @@ * Main test functions. */ -#include +#include #include "TrieHash.h" #include "MemTrie.h" diff --git a/test/libdevcrypto/MemTrie.cpp b/test/libdevcrypto/MemTrie.cpp index ab5a13b60..4507d1d80 100644 --- a/test/libdevcrypto/MemTrie.cpp +++ b/test/libdevcrypto/MemTrie.cpp @@ -21,8 +21,8 @@ #include "MemTrie.h" -#include -#include +#include +#include #include using namespace std; using namespace dev; diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 3381c45da..497887145 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/test/libdevcrypto/hexPrefix.cpp b/test/libdevcrypto/hexPrefix.cpp index c72f24535..223f1ac7b 100644 --- a/test/libdevcrypto/hexPrefix.cpp +++ b/test/libdevcrypto/hexPrefix.cpp @@ -27,7 +27,7 @@ #include "../JsonSpiritHeaders.h" #include #include -#include +#include #include "../TestHelper.h" using namespace std; diff --git a/test/libdevcrypto/trie.cpp b/test/libdevcrypto/trie.cpp index ecfc515aa..3d6d493dd 100644 --- a/test/libdevcrypto/trie.cpp +++ b/test/libdevcrypto/trie.cpp @@ -27,8 +27,8 @@ #include "../JsonSpiritHeaders.h" #include -#include -#include +#include +#include #include "MemTrie.h" #include "../TestHelper.h" diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 191b94cc3..4e98b4036 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -21,7 +21,7 @@ */ #include -#include +#include #include #include #include diff --git a/test/libp2p/rlpx.cpp b/test/libp2p/rlpx.cpp index 6a86652fb..620ddd952 100644 --- a/test/libp2p/rlpx.cpp +++ b/test/libp2p/rlpx.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index aa51a674d..90ce20d26 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include using namespace std; diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 4ec7b8bda..c52bbf9de 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 12625ffbc..3cfc016e3 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include From 715a63620bd9ac7a51164f45dec2a694962b7ab1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 20:04:48 +0200 Subject: [PATCH 28/70] Move OverlayDB (leveldb dependent) back into libdevcrypto. --- libdevcore/TrieDB.h | 1 - {libdevcore => libdevcrypto}/OverlayDB.cpp | 0 {libdevcore => libdevcrypto}/OverlayDB.h | 2 +- libethereum/CachedAddressState.cpp | 7 ++++--- libethereum/State.h | 1 + test/deprecated/main.cpp | 4 ---- 6 files changed, 6 insertions(+), 9 deletions(-) rename {libdevcore => libdevcrypto}/OverlayDB.cpp (100%) rename {libdevcore => libdevcrypto}/OverlayDB.h (97%) diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 13a520311..f9d7bff5f 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -32,7 +32,6 @@ #include #include #include "MemoryDB.h" -#include "OverlayDB.h" #include "TrieCommon.h" namespace ldb = leveldb; diff --git a/libdevcore/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp similarity index 100% rename from libdevcore/OverlayDB.cpp rename to libdevcrypto/OverlayDB.cpp diff --git a/libdevcore/OverlayDB.h b/libdevcrypto/OverlayDB.h similarity index 97% rename from libdevcore/OverlayDB.h rename to libdevcrypto/OverlayDB.h index 2e5428bdf..b37d2c11b 100644 --- a/libdevcore/OverlayDB.h +++ b/libdevcrypto/OverlayDB.h @@ -29,7 +29,7 @@ #include #include #include -#include "MemoryDB.h" +#include namespace ldb = leveldb; namespace dev diff --git a/libethereum/CachedAddressState.cpp b/libethereum/CachedAddressState.cpp index 7c2f0a80c..757aef466 100644 --- a/libethereum/CachedAddressState.cpp +++ b/libethereum/CachedAddressState.cpp @@ -21,8 +21,9 @@ #include "CachedAddressState.h" -#include #include +#include +#include #include "Account.h" using namespace std; using namespace dev; @@ -57,8 +58,8 @@ std::unordered_map CachedAddressState::storage() const if (m_r) { SecureTrieDB memdb(const_cast(m_o), m_r[2].toHash()); // promise we won't alter the overlay! :) -// for (auto const& j: memdb) -// ret[j.first] = RLP(j.second).toInt(); + for (auto const& j: memdb) + ret[j.first] = RLP(j.second).toInt(); } if (m_s) for (auto const& j: m_s->storageOverlay()) diff --git a/libethereum/State.h b/libethereum/State.h index 971c2220a..f46d0e222 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/test/deprecated/main.cpp b/test/deprecated/main.cpp index 6cb098228..47e96f337 100644 --- a/test/deprecated/main.cpp +++ b/test/deprecated/main.cpp @@ -20,10 +20,6 @@ * Main test functions. */ -#include -#include "TrieHash.h" -#include "MemTrie.h" - #include int trieTest(); From c4df26e82ed48138e5e8cf9323467f3113bc4506 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 22:15:23 +0200 Subject: [PATCH 29/70] Actually load the DAG. --- alethzero/MainWin.cpp | 2 +- ethminer/MinerAux.h | 12 ++++++------ libethcore/EthashAux.cpp | 6 +++--- libethcore/EthashAux.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b59e9ce1f..a09966679 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1166,7 +1166,7 @@ void Main::on_turboMining_triggered() void Main::refreshBlockChain() { - if (!ui->blocks->isVisible()) + if (!ui->blocks->isVisible() || !isVisible()) return; DEV_TIMED_FUNCTION; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 8e480a3ff..53a5fa7e4 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -388,7 +388,7 @@ private: (void)_m; (void)_remote; (void)_recheckPeriod; - #if ETH_JSONRPC || !ETH_TRUE +#if ETH_JSONRPC || !ETH_TRUE jsonrpc::HttpClient client(_remote); Farm rpc(client); @@ -399,7 +399,7 @@ private: f.startGPU(); ProofOfWork::WorkPackage current; - EthashAux::FullType dag; + EthashAux::FullType dag; while (true) try { @@ -418,9 +418,9 @@ private: cnote << "Getting work package..."; Json::Value v = rpc.eth_getWork(); h256 hh(v[0].asString()); - h256 newSeedHash(v[1].asString()); - if (!(dag = EthashAux::full(newSeedHash, true))) - BOOST_THROW_EXCEPTION(DAGCreationFailure()); + h256 newSeedHash(v[1].asString()); + if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; }))) + BOOST_THROW_EXCEPTION(DAGCreationFailure()); if (hh != current.headerHash) { current.headerHash = hh; @@ -459,7 +459,7 @@ private: cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r"; cerr << endl; } - #endif +#endif exit(0); } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 38425aca2..a94c1237d 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -167,7 +167,7 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } - if (_createIfMissing || computeFull(_seedHash) == 100) + if (_createIfMissing || computeFull(_seedHash, false) == 100) { s_dagCallback = _f; cnote << "Loading from libethash..."; @@ -183,7 +183,7 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing #define DEV_IF_THROWS(X) try { X; } catch (...) -unsigned EthashAux::computeFull(h256 const& _seedHash) +unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); uint64_t blockNumber; @@ -199,7 +199,7 @@ unsigned EthashAux::computeFull(h256 const& _seedHash) return 100; } - if (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable()) + if (_createIfMissing && (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable())) { get()->m_fullProgress = 0; get()->m_generatingFullNumber = blockNumber / ETHASH_EPOCH_LENGTH * ETHASH_EPOCH_LENGTH; diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index b09f6465f..e6fed519f 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -71,7 +71,7 @@ public: static const uint64_t NotGenerating = (uint64_t)-1; /// Kicks off generation of DAG for @a _seedHash and @returns false or @returns true if ready. - static unsigned computeFull(h256 const& _seedHash); + static unsigned computeFull(h256 const& _seedHash, bool _createIfMissing = true); /// Information on the generation progress. static std::pair fullGeneratingProgress() { return std::make_pair(get()->m_generatingFullNumber, get()->m_fullProgress); } /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. From c4b044d9263b7f425a0dd8acf080f61a5d082624 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 22:47:07 +0200 Subject: [PATCH 30/70] Improve AZ & eth latency. --- libethereum/BlockChain.cpp | 6 ++++-- libethereum/Client.cpp | 7 ++++++- libethereum/Client.h | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index c46127303..e23fde6b6 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -96,7 +96,7 @@ ldb::Slice dev::eth::toSlice(h256 const& _h, unsigned _sub) #endif } -#if ETH_DEBUG +#if ETH_DEBUG&&0 static const chrono::system_clock::duration c_collectionDuration = chrono::seconds(15); static const unsigned c_collectionQueueSize = 2; static const unsigned c_maxCacheSize = 1024 * 1024 * 1; @@ -318,7 +318,9 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st try { // Nonce & uncle nonces already verified thread at this point. - auto r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + ImportRoute r; + DEV_TIMED_ABOVE(Block import, 500) + r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); fresh += r.first; dead += r.second; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 97118a7a9..e39126713 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -172,6 +172,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for m_preMine(m_stateDB, BaseState::CanonGenesis), m_postMine(m_stateDB) { + m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); @@ -197,6 +198,7 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_preMine(m_stateDB), m_postMine(m_stateDB) { + m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); @@ -484,7 +486,7 @@ void Client::syncBlockQueue() cwork << "BQ ==> CHAIN ==> STATE"; { - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, 10); + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 90 + 10); if (ir.first.empty()) return; } @@ -601,6 +603,9 @@ void Client::onChainChanged(ImportRoute const& _ir) bool Client::remoteActive() const { + cnote << chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); + cnote << chrono::duration_cast(m_lastGetWork.time_since_epoch()).count(); + cnote << chrono::duration_cast(chrono::system_clock::now() - m_lastGetWork).count(); return chrono::system_clock::now() - m_lastGetWork < chrono::seconds(30); } diff --git a/libethereum/Client.h b/libethereum/Client.h index 7eeb7fb2d..4fa6da8b1 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -289,7 +289,7 @@ private: BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). bool remoteActive() const; ///< Is there an active and valid remote worker? bool m_remoteWorking = false; ///< Has the remote worker recently been reset? - std::chrono::system_clock::time_point m_lastGetWork = std::chrono::system_clock::time_point::min(); ///< Is there an active and valid remote worker? + std::chrono::system_clock::time_point m_lastGetWork; ///< Is there an active and valid remote worker? std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. From 3c58d68fe28c9a4fd9eeb21aa432225c5e947bc7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 22:47:59 +0200 Subject: [PATCH 31/70] Quieter timing reporting. --- alethzero/MainWin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a09966679..076e9d547 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1169,7 +1169,7 @@ void Main::refreshBlockChain() if (!ui->blocks->isVisible() || !isVisible()) return; - DEV_TIMED_FUNCTION; + DEV_TIMED_FUNCTION_ABOVE(500); cwatch << "refreshBlockChain()"; // TODO: keep the same thing highlighted. From 742f2dbcc8691581400be7ef2f5202046b5c321a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 23:04:54 +0200 Subject: [PATCH 32/70] Build fix. --- libdevcore/Common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 240746302..ac4d89103 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -201,7 +201,7 @@ private: #endif #define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false) -#define DEV_TIMED_SCOPE_ABOVE(S) ::dev::TimerHelper __eth_t(S, MS) +#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) #if WIN32 #define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) #else From ce205f382cb1f2964f1edcbbb08e43e93bd200c9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 23:22:44 +0200 Subject: [PATCH 33/70] Remote mining fixes. --- alethzero/MainWin.cpp | 2 +- ethminer/MinerAux.h | 2 ++ libethereum/BlockQueue.h | 2 +- libethereum/Client.cpp | 8 +++++++- libethereum/Client.h | 3 +++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 076e9d547..4f236b3e8 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1166,7 +1166,7 @@ void Main::on_turboMining_triggered() void Main::refreshBlockChain() { - if (!ui->blocks->isVisible() || !isVisible()) + if (!ui->blocks->isVisible() && isVisible()) return; DEV_TIMED_FUNCTION_ABOVE(500); diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 53a5fa7e4..d99e36976 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -419,6 +419,8 @@ private: Json::Value v = rpc.eth_getWork(); h256 hh(v[0].asString()); h256 newSeedHash(v[1].asString()); + if (current.seedHash != newSeedHash) + cnote << "Grabbing DAG for" << newSeedHash; if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; }))) BOOST_THROW_EXCEPTION(DAGCreationFailure()); if (hh != current.headerHash) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index c865bac32..d0437739d 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -94,7 +94,7 @@ public: void retryAllUnknown(); /// Get information on the items queued. - std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_verified.size(), m_unknown.size()); } + std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_readySet.size(), m_unknownSet.size()); } /// Clear everything. void clear() { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; Guard l2(m_verification); m_readySet.clear(); m_drainingSet.clear(); m_verified.clear(); m_unverified.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e39126713..0fd27520d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -455,8 +455,13 @@ ProofOfWork::WorkPackage Client::getWork() { // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); m_lastGetWork = chrono::system_clock::now(); m_remoteWorking = true; + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); return ProofOfWork::package(m_miningInfo); } @@ -612,7 +617,8 @@ bool Client::remoteActive() const void Client::onPostStateChanged() { cnote << "Post state changed"; - if (isMining() || remoteActive()) + + if (m_bq.items().first == 0 && (isMining() || remoteActive())) { cnote << "Restarting mining..."; DEV_WRITE_GUARDED(x_working) diff --git a/libethereum/Client.h b/libethereum/Client.h index 4fa6da8b1..c77cb6034 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -274,6 +274,9 @@ private: /// Ticks various system-level objects. void tick(); + /// @returns true only if it's worth bothering to prep the mining block. + bool shouldServeWork() const { return m_bq.items().first == 0 && (isMining() || remoteActive()); } + VersionChecker m_vc; ///< Dummy object to check & update the protocol version. CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). From cfb9bd15b02e0d7c914cb00b8216d44089b11b37 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 May 2015 23:29:13 +0200 Subject: [PATCH 34/70] Tidy up notifications. --- alethzero/MainWin.cpp | 2 +- libethcore/Miner.h | 10 ++++------ libethereum/Client.cpp | 5 +---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4f236b3e8..07f48c0bc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1353,7 +1353,7 @@ void Main::timerEvent(QTimerEvent*) auto ls = ethereum()->checkWatchSafe(i.first); if (ls.size()) { - cnote << "FIRING WATCH" << i.first << ls.size(); +// cnote << "FIRING WATCH" << i.first << ls.size(); i.second(ls); } } diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 3a68491ff..cede34475 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -107,12 +107,10 @@ public: } if (!!_work) { - boost::timer t; - pause(); - cdebug << "pause took" << t.elapsed(); - t.restart(); - kickOff(); - cdebug << "kickOff took" << t.elapsed(); + DEV_TIMED_ABOVE(pause, 250) + pause(); + DEV_TIMED_ABOVE(kickOff, 250) + kickOff(); } else if (!_work && !!old) pause(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 0fd27520d..f10eda55a 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -608,9 +608,6 @@ void Client::onChainChanged(ImportRoute const& _ir) bool Client::remoteActive() const { - cnote << chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); - cnote << chrono::duration_cast(m_lastGetWork.time_since_epoch()).count(); - cnote << chrono::duration_cast(chrono::system_clock::now() - m_lastGetWork).count(); return chrono::system_clock::now() - m_lastGetWork < chrono::seconds(30); } @@ -647,7 +644,7 @@ void Client::noteChanged(h256Hash const& _filters) { Guard l(x_filtersWatches); if (_filters.size()) - filtersStreamOut(cnote << "noteChanged:", _filters); + filtersStreamOut(cwatch << "noteChanged:", _filters); // accrue all changes left in each filter into the watches. for (auto& w: m_watches) if (_filters.count(w.second.id)) From 31c6ee40f6a752558ce35e0b1f10a0c12a66c676 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 20 May 2015 00:27:07 +0200 Subject: [PATCH 35/70] Gas estimation taking known state into account. --- libevmasm/Assembly.cpp | 1 + libevmasm/AssemblyItem.h | 6 + libevmasm/GasMeter.cpp | 132 ++++++++++++++++-- libevmasm/GasMeter.h | 27 +++- libevmasm/KnownState.cpp | 13 +- libevmasm/KnownState.h | 4 + libsolidity/ASTVisitor.h | 20 +++ libsolidity/CompilerStack.cpp | 38 ++--- libsolidity/CompilerStack.h | 5 +- libsolidity/StructuralGasEstimator.cpp | 39 +++++- libsolidity/StructuralGasEstimator.h | 4 + test/{ => libsolidity}/GasMeter.cpp | 60 +++++++- test/libsolidity/solidityExecutionFramework.h | 11 +- 13 files changed, 315 insertions(+), 45 deletions(-) rename test/{ => libsolidity}/GasMeter.cpp (66%) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 6f38b0f42..5cf3b787a 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -431,6 +431,7 @@ bytes Assembly::assemble() const case PushSubSize: { auto s = m_data[i.data()].size(); + i.setPushedValue(u256(s)); byte b = max(1, dev::bytesRequired(s)); ret.push_back((byte)Instruction::PUSH1 - 1 + b); ret.resize(ret.size() + b); diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index b3012a7ea..7d8f3d9a4 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -84,11 +84,17 @@ public: JumpType getJumpType() const { return m_jumpType; } std::string getJumpTypeAsString() const; + void setPushedValue(u256 const& _value) const { m_pushedValue = std::make_shared(_value); } + u256 const* pushedValue() const { return m_pushedValue.get(); } + private: AssemblyItemType m_type; u256 m_data; SourceLocation m_location; JumpType m_jumpType = JumpType::Ordinary; + /// Pushed value for operations with data to be determined during assembly stage, + /// e.g. PushSubSize, PushTag, PushSub, etc. + mutable std::shared_ptr m_pushedValue; }; using AssemblyItems = std::vector; diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index e5fb0e09a..a8dc4dd58 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -20,6 +20,7 @@ */ #include "GasMeter.h" +#include #include using namespace std; @@ -41,55 +42,162 @@ GasMeter::GasConsumption& GasMeter::GasConsumption::operator+=(GasConsumption co GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item) { - switch (_item.type()) { + GasConsumption gas; + switch (_item.type()) + { case Push: case PushTag: - return runGas(Instruction::PUSH1); + case PushData: + case PushString: + case PushSub: + case PushSubSize: + case PushProgramSize: + gas = runGas(Instruction::PUSH1); + break; case Tag: - return runGas(Instruction::JUMPDEST); + gas = runGas(Instruction::JUMPDEST); + break; case Operation: { - GasConsumption gas = runGas(_item.instruction()); + ExpressionClasses& classes = m_state->expressionClasses(); + gas = runGas(_item.instruction()); switch (_item.instruction()) { case Instruction::SSTORE: - // @todo logic can be improved - gas += c_sstoreSetGas; + { + ExpressionClasses::Id slot = m_state->relativeStackElement(0); + ExpressionClasses::Id value = m_state->relativeStackElement(-1); + if (classes.knownZero(value) || ( + m_state->storageContent().count(slot) && + classes.knownNonZero(m_state->storageContent().at(slot)) + )) + gas += c_sstoreResetGas; //@todo take refunds into account + else + gas += c_sstoreSetGas; break; + } case Instruction::SLOAD: gas += c_sloadGas; break; + case Instruction::RETURN: + gas += memoryGas(0, -1); + break; + case Instruction::MLOAD: case Instruction::MSTORE: + gas += memoryGas(classes.find(eth::Instruction::ADD, { + m_state->relativeStackElement(0), + classes.find(AssemblyItem(32)) + })); + break; case Instruction::MSTORE8: - case Instruction::MLOAD: - case Instruction::RETURN: + gas += memoryGas(classes.find(eth::Instruction::ADD, { + m_state->relativeStackElement(0), + classes.find(AssemblyItem(1)) + })); + break; case Instruction::SHA3: + gas = c_sha3Gas; + gas += wordGas(c_sha3WordGas, m_state->relativeStackElement(-1)); + gas += memoryGas(0, -1); + break; case Instruction::CALLDATACOPY: case Instruction::CODECOPY: + gas += memoryGas(0, -2); + gas += wordGas(c_copyGas, m_state->relativeStackElement(-2)); + break; case Instruction::EXTCODECOPY: + gas += memoryGas(-1, -3); + gas += wordGas(c_copyGas, m_state->relativeStackElement(-3)); + break; case Instruction::LOG0: case Instruction::LOG1: case Instruction::LOG2: case Instruction::LOG3: case Instruction::LOG4: + { + unsigned n = unsigned(_item.instruction()) - unsigned(Instruction::LOG0); + gas = c_logGas + c_logTopicGas * n; + gas += memoryGas(0, -1); + if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1))) + gas += c_logDataGas * (*value); + else + gas = GasConsumption::infinite(); + break; + } case Instruction::CALL: case Instruction::CALLCODE: + gas = c_callGas; + if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0))) + gas += (*value); + else + gas = GasConsumption::infinite(); + if (_item.instruction() != Instruction::CALLCODE) + gas += c_callNewAccountGas; // We very rarely know whether the address exists. + if (!classes.knownZero(m_state->relativeStackElement(-2))) + gas += c_callValueTransferGas; + gas += memoryGas(-3, -4); + gas += memoryGas(-5, -6); + break; case Instruction::CREATE: + gas = c_createGas; + gas += memoryGas(-1, -2); + break; case Instruction::EXP: - // @todo logic can be improved - gas = GasConsumption::infinite(); + gas = c_expGas; + if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1))) + gas += c_expByteGas * (32 - (h256(*value).firstBitSet() / 8)); + else + gas = GasConsumption::infinite(); break; default: break; } - return gas; break; } default: + gas = GasConsumption::infinite(); break; } - return GasConsumption::infinite(); + m_state->feedItem(_item); + return gas; +} + +GasMeter::GasConsumption GasMeter::wordGas(u256 const& _multiplier, ExpressionClasses::Id _position) +{ + u256 const* value = m_state->expressionClasses().knownConstant(_position); + if (!value) + return GasConsumption::infinite(); + return GasConsumption(_multiplier * ((*value + 31) / 32)); +} + +GasMeter::GasConsumption GasMeter::memoryGas(ExpressionClasses::Id _position) +{ + u256 const* value = m_state->expressionClasses().knownConstant(_position); + if (!value) + return GasConsumption::infinite(); + if (*value < m_largestMemoryAccess) + return GasConsumption(u256(0)); + u256 previous = m_largestMemoryAccess; + m_largestMemoryAccess = *value; + auto memGas = [](u256 const& pos) -> u256 + { + u256 size = (pos + 31) / 32; + return c_memoryGas * size + size * size / c_quadCoeffDiv; + }; + return memGas(*value) - memGas(previous); +} + +GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosSize) +{ + ExpressionClasses& classes = m_state->expressionClasses(); + if (classes.knownZero(m_state->relativeStackElement(_stackPosSize))) + return GasConsumption(0); + else + return memoryGas(classes.find(eth::Instruction::ADD, { + m_state->relativeStackElement(_stackPosOffset), + m_state->relativeStackElement(_stackPosSize) + })); } GasMeter::GasConsumption GasMeter::runGas(Instruction _instruction) diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index 63dbc1380..ab6d5613b 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include namespace dev @@ -29,8 +30,13 @@ namespace dev namespace eth { +class KnownState; + /** * Class that helps computing the maximum gas consumption for instructions. + * Has to be initialized with a certain known state that will be automatically updated for + * each call to estimateMax. These calls have to supply strictly subsequent AssemblyItems. + * A new gas meter has to be constructed (with a new state) for control flow changes. */ class GasMeter { @@ -47,11 +53,28 @@ public: bool isInfinite; }; - /// Returns an upper bound on the gas consumed by the given instruction. + /// Constructs a new gas meter given the current state. + GasMeter(std::shared_ptr const& _state): m_state(_state) {} + + /// @returns an upper bound on the gas consumed by the given instruction and updates + /// the state. GasConsumption estimateMax(AssemblyItem const& _item); private: + /// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise. + GasConsumption wordGas(u256 const& _multiplier, ExpressionClasses::Id _value); + /// @returns the gas needed to access the given memory position. + /// @todo this assumes that memory was never accessed before and thus over-estimates gas usage. + GasConsumption memoryGas(ExpressionClasses::Id _position); + /// @returns the memory gas for accessing the memory at a specific offset for a number of bytes + /// given as values on the stack at the given relative positions. + GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize); + static GasConsumption runGas(Instruction _instruction); + + std::shared_ptr m_state; + /// Largest point where memory was accessed since the creation of this object. + u256 m_largestMemoryAccess; }; inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption const& _consumption) @@ -59,7 +82,7 @@ inline std::ostream& operator<<(std::ostream& _str, GasMeter::GasConsumption con if (_consumption.isInfinite) return _str << "inf"; else - return _str << _consumption.value; + return _str << std::dec << _consumption.value; } diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 895778ed1..d62dbf17e 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -92,7 +92,11 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool else if (_item.type() != Operation) { assertThrow(_item.deposit() == 1, InvalidDeposit, ""); - setStackElement(++m_stackHeight, m_expressionClasses->find(_item, {}, _copyItem)); + if (_item.pushedValue()) + // only available after assembly stage, should not be used for optimisation + setStackElement(++m_stackHeight, m_expressionClasses->find(*_item.pushedValue())); + else + setStackElement(++m_stackHeight, m_expressionClasses->find(_item, {}, _copyItem)); } else { @@ -230,7 +234,12 @@ ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation return m_stackElements.at(_stackHeight); // Stack element not found (not assigned yet), create new unknown equivalence class. return m_stackElements[_stackHeight] = - m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); + m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); +} + +KnownState::Id KnownState::relativeStackElement(int _stackOffset, SourceLocation const& _location) +{ + return stackElement(m_stackHeight + _stackOffset, _location); } void KnownState::clearTagUnions() diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h index 3505df74f..9d28ef21a 100644 --- a/libevmasm/KnownState.h +++ b/libevmasm/KnownState.h @@ -111,6 +111,8 @@ public: /// Retrieves the current equivalence class fo the given stack element (or generates a new /// one if it does not exist yet). Id stackElement(int _stackHeight, SourceLocation const& _location); + /// @returns the stackElement relative to the current stack height. + Id relativeStackElement(int _stackOffset, SourceLocation const& _location = SourceLocation()); /// @returns its set of tags if the given expression class is a known tag union; returns a set /// containing the tag if it is a PushTag expression and the empty set otherwise. @@ -123,6 +125,8 @@ public: std::map const& stackElements() const { return m_stackElements; } ExpressionClasses& expressionClasses() const { return *m_expressionClasses; } + std::map const& storageContent() const { return m_storageContent; } + private: /// Assigns a new equivalence class to the next sequence number of the given stack element. void setStackElement(int _stackHeight, Id _class); diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index fbda50791..f78472208 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -220,6 +220,26 @@ protected: virtual void endVisitNode(ASTNode const&) { } }; +/** + * Utility class that accepts std::functions and calls them for visitNode and endVisitNode. + */ +class SimpleASTVisitor: public ASTConstVisitor +{ +public: + SimpleASTVisitor( + std::function _onVisit, + std::function _onEndVisit + ): m_onVisit(_onVisit), m_onEndVisit(_onEndVisit) {} + +protected: + virtual bool visitNode(ASTNode const& _n) override { return m_onVisit ? m_onVisit(_n) : true; } + virtual void endVisitNode(ASTNode const& _n) override { m_onEndVisit(_n); } + +private: + std::function m_onVisit; + std::function m_onEndVisit; +}; + /** * Utility class that visits the AST in depth-first order and calls a function on each node and each edge. * Child nodes are only visited if the node callback of the parent returns true. diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index bffa4158f..4f9764075 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -55,12 +55,29 @@ const map StandardSources = map{ }; CompilerStack::CompilerStack(bool _addStandardSources): - m_addStandardSources(_addStandardSources), m_parseSuccessful(false) + m_parseSuccessful(false) { - if (m_addStandardSources) + if (_addStandardSources) addSources(StandardSources, true); // add them as libraries } +void CompilerStack::reset(bool _keepSources, bool _addStandardSources) +{ + m_parseSuccessful = false; + if (_keepSources) + for (auto sourcePair: m_sources) + sourcePair.second.reset(); + else + { + m_sources.clear(); + if (_addStandardSources) + addSources(StandardSources, true); + } + m_globalContext.reset(); + m_sourceOrder.clear(); + m_contracts.clear(); +} + bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) { bool existed = m_sources.count(_name) != 0; @@ -269,23 +286,6 @@ tuple CompilerStack::positionFromSourceLocation(SourceLocati return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn); } -void CompilerStack::reset(bool _keepSources) -{ - m_parseSuccessful = false; - if (_keepSources) - for (auto sourcePair: m_sources) - sourcePair.second.reset(); - else - { - m_sources.clear(); - if (m_addStandardSources) - addSources(StandardSources, true); - } - m_globalContext.reset(); - m_sourceOrder.clear(); - m_contracts.clear(); -} - void CompilerStack::resolveImports() { // topological sorting (depth first search) of the import graph, cutting potential cycles diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 2ad791f22..0bc109a26 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -72,6 +72,9 @@ public: /// Creates a new compiler stack. Adds standard sources if @a _addStandardSources. explicit CompilerStack(bool _addStandardSources = true); + /// Resets the compiler to a state where the sources are not parsed or even removed. + void reset(bool _keepSources = false, bool _addStandardSources = true); + /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// @returns true if a source object by the name already existed and was replaced. void addSources(StringMap const& _nameContents, bool _isLibrary = false) { for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary); } @@ -165,13 +168,11 @@ private: Contract(); }; - void reset(bool _keepSources = false); void resolveImports(); Contract const& getContract(std::string const& _contractName = "") const; Source const& getSource(std::string const& _sourceName = "") const; - bool m_addStandardSources; ///< If true, standard sources are added. bool m_parseSuccessful; std::map m_sources; std::shared_ptr m_globalContext; diff --git a/libsolidity/StructuralGasEstimator.cpp b/libsolidity/StructuralGasEstimator.cpp index ececd7116..9ce32ca54 100644 --- a/libsolidity/StructuralGasEstimator.cpp +++ b/libsolidity/StructuralGasEstimator.cpp @@ -23,6 +23,9 @@ #include "StructuralGasEstimator.h" #include #include +#include +#include +#include #include #include @@ -38,14 +41,23 @@ StructuralGasEstimator::ASTGasConsumptionSelfAccumulated StructuralGasEstimator: { solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, ""); map particularCosts; - GasMeter meter; - for (auto const& item: _items) - particularCosts[item.getLocation()] += meter.estimateMax(item); + ControlFlowGraph cfg(_items); + for (BasicBlock const& block: cfg.optimisedBlocks()) + { + assertThrow(!!block.startState, OptimizerException, ""); + GasMeter meter(block.startState->copy()); + auto const end = _items.begin() + block.end; + for (auto iter = _items.begin() + block.begin; iter != end; ++iter) + particularCosts[iter->getLocation()] += meter.estimateMax(*iter); + } + set finestNodes = finestNodesAtLocation(_ast); ASTGasConsumptionSelfAccumulated gasCosts; auto onNode = [&](ASTNode const& _node) { + if (!finestNodes.count(&_node)) + return true; gasCosts[&_node][0] = gasCosts[&_node][1] = particularCosts[_node.getLocation()]; return true; }; @@ -108,3 +120,24 @@ map StructuralGasEstimator::breakToSta // gasCosts should only contain non-overlapping locations return gasCosts; } + +set StructuralGasEstimator::finestNodesAtLocation( + vector const& _roots +) +{ + map locations; + set nodes; + SimpleASTVisitor visitor(function(), [&](ASTNode const& _n) + { + if (!locations.count(_n.getLocation())) + { + locations[_n.getLocation()] = &_n; + nodes.insert(&_n); + } + }); + + for (ASTNode const* root: _roots) + root->accept(visitor); + return nodes; +} + diff --git a/libsolidity/StructuralGasEstimator.h b/libsolidity/StructuralGasEstimator.h index df1ae509d..ddc7c186c 100644 --- a/libsolidity/StructuralGasEstimator.h +++ b/libsolidity/StructuralGasEstimator.h @@ -56,6 +56,10 @@ public: ASTGasConsumptionSelfAccumulated const& _gasCosts, std::vector const& _roots ); + +private: + /// @returns the set of AST nodes which are the finest nodes at their location. + std::set finestNodesAtLocation(std::vector const& _roots); }; } diff --git a/test/GasMeter.cpp b/test/libsolidity/GasMeter.cpp similarity index 66% rename from test/GasMeter.cpp rename to test/libsolidity/GasMeter.cpp index 0ffe41712..43eb3f956 100644 --- a/test/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -21,6 +21,8 @@ */ #include +#include +#include #include #include #include @@ -55,8 +57,21 @@ public: ); } + void testCreationTimeGas(string const& _sourceCode, string const& _contractName = "") + { + compileAndRun(_sourceCode); + auto state = make_shared(); + GasMeter meter(state); + GasMeter::GasConsumption gas; + for (AssemblyItem const& item: *m_compiler.getAssemblyItems(_contractName)) + gas += meter.estimateMax(item); + u256 bytecodeSize(m_compiler.getRuntimeBytecode(_contractName).size()); + gas += bytecodeSize * c_createDataGas; + BOOST_REQUIRE(!gas.isInfinite); + BOOST_CHECK(gas.value == m_gasUsed); + } + protected: - dev::solidity::CompilerStack m_compiler; map m_gasCosts; }; @@ -91,6 +106,49 @@ BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs) } } +BOOST_AUTO_TEST_CASE(simple_contract) +{ + // Tests a simple "deploy contract" code without constructor. The actual contract is not relevant. + char const* sourceCode = R"( + contract test { + bytes32 public shaValue; + function f(uint a) { + shaValue = sha3(a); + } + } + )"; + testCreationTimeGas(sourceCode); +} + +BOOST_AUTO_TEST_CASE(store_sha3) +{ + char const* sourceCode = R"( + contract test { + bytes32 public shaValue; + function test(uint a) { + shaValue = sha3(a); + } + } + )"; + testCreationTimeGas(sourceCode); +} + +BOOST_AUTO_TEST_CASE(updating_store) +{ + char const* sourceCode = R"( + contract test { + uint data; + uint data2; + function test() { + data = 1; + data = 2; + data2 = 0; + } + } + )"; + testCreationTimeGas(sourceCode); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index f76465f23..fa25fb12c 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -44,11 +44,11 @@ public: bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { - dev::solidity::CompilerStack compiler(m_addStandardSources); - compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(compiler.compile(m_optimize), "Compiling contract failed"); + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - bytes code = compiler.getBytecode(_contractName); + bytes code = m_compiler.getBytecode(_contractName); sendMessage(code, true, _value); BOOST_REQUIRE(!m_output.empty()); return m_output; @@ -160,12 +160,14 @@ protected: BOOST_REQUIRE(executive.go()); m_state.noteSending(m_sender); executive.finalize(); + m_gasUsed = executive.gasUsed(); m_output = executive.out().toVector(); m_logs = executive.logs(); } bool m_optimize = false; bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; Address m_sender; Address m_contractAddress; eth::State m_state; @@ -173,6 +175,7 @@ protected: u256 const m_gas = 100000000; bytes m_output; eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 846de9aceaca7fae862c2fbe7b6fb5612e80a5b2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 09:31:38 +0200 Subject: [PATCH 36/70] Pregenerate DAG when mining on AZ/eth/ethminer. Use regeneratable key for decrets by default. --- ethminer/MinerAux.h | 9 ++++++++- libethcore/Ethash.cpp | 8 ++++++++ libethcore/Ethash.h | 1 + libethereum/Client.cpp | 6 +++++- libethereum/Executive.cpp | 36 ++++++++++++++++++++++++++++++++++++ libethereum/Executive.h | 1 + libethereum/ExtVM.cpp | 10 +++++----- libethereum/ExtVM.h | 2 +- libethereum/KeyManager.cpp | 3 +++ libethereum/KeyManager.h | 10 ++++++++-- libevm/ExtVMFace.h | 14 +++++++++++++- libevm/VM.cpp | 26 +++++++++++++++++++------- test/libevm/vm.cpp | 7 ++----- test/libevm/vm.h | 2 +- 14 files changed, 111 insertions(+), 24 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index d99e36976..ef0621b7f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -174,6 +174,10 @@ public: m_minerType = MinerType::GPU; miningThreads = 1; } + else if (arg == "--no-precompute") + { + precompute = false; + } else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc) { string m = boost::to_lower_copy(string(argv[++i])); @@ -268,6 +272,7 @@ public: << "Work farming mode:" << endl << " -F,--farm Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8545)" << endl << " --farm-recheck Leave n ms between checks for changed work (default: 500)." << endl + << " --no-precompute Don't precompute the next epoch's DAG." << endl #endif << "Ethash verify mode:" << endl << " -w,--check-pow Check PoW credentials for validity." << endl @@ -423,6 +428,8 @@ private: cnote << "Grabbing DAG for" << newSeedHash; if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; }))) BOOST_THROW_EXCEPTION(DAGCreationFailure()); + if (precompute) + EthashAux::computeFull(sha3(newSeedHash), true); if (hh != current.headerHash) { current.headerHash = hh; @@ -486,5 +493,5 @@ private: /// Farm params string farmURL = "http://127.0.0.1:8545"; unsigned farmRecheckPeriod = 500; - + bool precompute = true; }; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 1f16166f0..228f03f8e 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -75,6 +75,13 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) return ret; } +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); +} + void Ethash::prep(BlockInfo const& _header, std::function const& _f) { EthashAux::full(_header.seedHash(), true, _f); @@ -306,6 +313,7 @@ void Ethash::GPUMiner::workLoop() cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash; if (!m_miner || m_minerSeed != w.seedHash) { + cnote << "Initialising miner..."; m_minerSeed = w.seedHash; delete m_miner; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 81f842e4f..86540678f 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -74,6 +74,7 @@ public: static std::string name(); static unsigned revision(); static void prep(BlockInfo const& _header, std::function const& _f = std::function()); + static void ensurePrecomputed(unsigned _number); static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index f10eda55a..e372e611a 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -457,11 +457,13 @@ ProofOfWork::WorkPackage Client::getWork() // this will be reset as soon as a new block arrives, allowing more transactions to be processed. bool oldShould = shouldServeWork(); m_lastGetWork = chrono::system_clock::now(); - m_remoteWorking = true; // if this request has made us bother to serve work, prep it now. if (!oldShould && shouldServeWork()) onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; return ProofOfWork::package(m_miningInfo); } @@ -627,6 +629,8 @@ void Client::onPostStateChanged() m_miningInfo = m_postMine.info(); } m_farm.setWork(m_miningInfo); + + Ethash::ensurePrecomputed(m_bc.number()); } m_remoteWorking = false; } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index a1eee9440..4fbf51244 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -159,6 +159,42 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen return !m_ext; } +bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin) +{ + m_isCreation = false; +// cnote << "Transferring" << formatBalance(_value) << "to receiver."; + auto it = !(_p.codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_p.codeAddress) : precompiled().end(); + if (it != precompiled().end()) + { + bigint g = it->second.gas(_p.data); + if (_p.gas < g) + { + m_endGas = 0; + m_excepted = TransactionException::OutOfGasBase; + // Bail from exception. + return true; // true actually means "all finished - nothing more to be done regarding go(). + } + else + { + m_endGas = (u256)(_p.gas - g); + m_precompiledOut = it->second.exec(_p.data); + m_out = &m_precompiledOut; + } + } + else if (m_s.addressHasCode(_p.codeAddress)) + { + m_vm = VMFactory::create(_p.gas); + bytes const& c = m_s.code(_p.codeAddress); + m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth); + } + else + m_endGas = _p.gas; + + m_s.transferBalance(_p.senderAddress, _p.receiveAddress, _p.value); + + return !m_ext; +} + bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin) { m_isCreation = true; diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 3806221be..8bb0ab771 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -95,6 +95,7 @@ public: /// Set up the executive for evaluating a bare CALL (message call) operation. /// @returns false iff go() must be called (and thus a VM execution in required). bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); + bool call(CallParameters const& _cp, u256 const& _gasPrice, Address const& _origin); /// Finalise an operation through accruing the substate into the parent context. void accrueSubState(SubState& _parentContext); diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index 68d146ce1..c0591cef5 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -26,16 +26,16 @@ using namespace std; using namespace dev; using namespace dev::eth; -bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp, Address _myAddressOverride, Address _codeAddressOverride) +bool ExtVM::call(CallParameters& _p) { Executive e(m_s, lastHashes, depth + 1); - if (!e.call(_receiveAddress, _codeAddressOverride, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, io_gas, origin)) + if (!e.call(_p, gasPrice, origin)) { - e.go(_onOp); + e.go(_p.onOp); e.accrueSubState(sub); } - io_gas = e.endGas(); - e.out().copyTo(_out); + _p.gas = e.endGas(); + e.out().copyTo(_p.out); return !e.excepted(); } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index 1a2d180dd..babff4edf 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -58,7 +58,7 @@ public: virtual h160 create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc const& _onOp = {}) override final; /// Create a new message call. Leave _myAddressOverride as the default to use the present address as caller. - virtual bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp = {}, Address _myAddressOverride = {}, Address _codeAddressOverride = {}) override final; + virtual bool call(CallParameters& _params) override final; /// Read address's balance. virtual u256 balance(Address _a) override final { return m_s.balance(_a); } diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp index cba6f4325..8c3fd28c3 100644 --- a/libethereum/KeyManager.cpp +++ b/libethereum/KeyManager.cpp @@ -71,6 +71,7 @@ bool KeyManager::load(std::string const& _pass) m_password = (string)s[3]; } m_cachedPasswords[hashPassword(m_password)] = m_password; + m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword(); return true; } catch (...) { @@ -214,4 +215,6 @@ void KeyManager::write(h128 const& _key, std::string const& _keysFile) const writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); m_key = _key; + m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword(); + } diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index bb537e1f1..0a83fcc00 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -75,10 +75,11 @@ public: Address address(h128 const& _uuid) const; h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo); - h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, m_password, std::string()); } + h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); } SecretStore& store() { return m_store; } void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo); + void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); } Secret secret(Address const& _address, std::function const& _pass = DontKnowThrow) const; Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; @@ -87,6 +88,7 @@ public: void kill(Address const& _a); private: + std::string defaultPassword() const { return asString(m_key.ref()); } h256 hashPassword(std::string const& _pass) const; // Only use if previously loaded ok. @@ -103,7 +105,11 @@ private: // Passwords that we're storing. mutable std::unordered_map m_cachedPasswords; - // The default password for keys in the keystore - protected by the master password. + // DEPRECATED. + // Used to be the default password for keys in the keystore, stored in the keys file. + // Now the default password is based off the key of the keys file directly, so this is redundant + // except for the fact that people have existing keys stored with it. Leave for now until/unless + // we have an upgrade strategy. std::string m_password; SecretStore m_store; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 8ebfd8fa5..ce259bef2 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -108,6 +108,18 @@ using LastHashes = std::vector; using OnOpFunc = std::function; +struct CallParameters +{ + Address senderAddress; + Address codeAddress; + Address receiveAddress; + u256 gas; + u256 value; + bytesConstRef data; + bytesRef out; + OnOpFunc onOp; +}; + /** * @brief Interface and null implementation of the class for specifying VM externalities. */ @@ -153,7 +165,7 @@ public: virtual h160 create(u256, u256&, bytesConstRef, OnOpFunc const&) { return h160(); } /// Make a new message call. - virtual bool call(Address, u256, bytesConstRef, u256&, bytesRef, OnOpFunc const&, Address, Address) { return false; } + virtual bool call(CallParameters&) { return false; } /// Revert any changes made (by any of the other calls). virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 368d27389..27650e3ad 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -56,6 +56,8 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { m_stack.reserve((unsigned)c_stackLimit); + unique_ptr callParams; + static const array c_metrics = metrics(); auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; @@ -626,13 +628,16 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) case Instruction::CALL: case Instruction::CALLCODE: { - u256 gas = m_stack.back(); + if (!callParams) + callParams.reset(new CallParameters); + + callParams->gas = m_stack.back(); if (m_stack[m_stack.size() - 3] > 0) - gas += c_callStipend; + callParams->gas += c_callStipend; m_stack.pop_back(); - Address receiveAddress = asAddress(m_stack.back()); + callParams->receiveAddress = asAddress(m_stack.back()); m_stack.pop_back(); - u256 value = m_stack.back(); + callParams->value = m_stack.back(); m_stack.pop_back(); unsigned inOff = (unsigned)m_stack.back(); @@ -644,12 +649,19 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) unsigned outSize = (unsigned)m_stack.back(); m_stack.pop_back(); - if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) - m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress)); + if (_ext.balance(_ext.myAddress) >= callParams->value && _ext.depth < 1024) + { + callParams->onOp = _onOp; + callParams->senderAddress = _ext.myAddress; + callParams->codeAddress = inst == Instruction::CALL ? callParams->receiveAddress : callParams->senderAddress; + callParams->data = bytesConstRef(m_temp.data() + inOff, inSize); + callParams->out = bytesRef(m_temp.data() + outOff, outSize); + m_stack.push_back(_ext.call(*callParams)); + } else m_stack.push_back(0); - m_gas += gas; + m_gas += callParams->gas; break; } case Instruction::RETURN: diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 10670bfe3..bda751af4 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -44,13 +44,10 @@ h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpF return na; } -bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256& io_gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) +bool FakeExtVM::call(CallParameters& _p) { - Transaction t(_value, gasPrice, io_gas, _receiveAddress, _data.toVector()); + Transaction t(_p.value, gasPrice, _p.gas, _p.receiveAddress, _p.data.toVector()); callcreates.push_back(t); - (void)_out; - (void)_myAddressOverride; - (void)_codeAddressOverride; return true; } diff --git a/test/libevm/vm.h b/test/libevm/vm.h index dff89d98d..18fa1ca25 100644 --- a/test/libevm/vm.h +++ b/test/libevm/vm.h @@ -59,7 +59,7 @@ public: virtual void suicide(Address _a) override { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); } virtual bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); } virtual h160 create(u256 _endowment, u256& io_gas, bytesConstRef _init, eth::OnOpFunc const&) override; - virtual bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256& io_gas, bytesRef _out, eth::OnOpFunc const&, Address, Address) override; + virtual bool call(eth::CallParameters&) override; void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data); void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); void set(Address _a, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); From 32a850a9ff42d775f0d0ee0868db88f4f748504d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 09:59:18 +0200 Subject: [PATCH 37/70] Trie timing. --- exp/main.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index d31306496..47efe576a 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,9 @@ #include #include #include +#include +#include +/* #include #include #include @@ -41,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -55,17 +57,43 @@ #include #include #include -#include +#include */ using namespace std; using namespace dev; -using namespace dev::eth; +/*using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; - +*/ #if 1 +int main() +{ + cdebug << "EXP"; + vector data; + for (unsigned i = 0; i < 10000; ++i) + data.push_back(rlp(i)); + + h256 ret; + DEV_TIMED(triedb) + { + MemoryDB mdb; + GenericTrieDB t(&mdb); + t.init(); + unsigned i = 0; + for (auto const& d: data) + t.insert(rlp(i++), d); + ret = t.root(); + } + cdebug << ret; + DEV_TIMED(hash256) + ret = orderedTrieRoot(data); + cdebug << ret; +} + +#elif 0 + int main() { KeyManager keyman; From b5822c7d9549c2e541a7165c48c5587b7dc19359 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 20 May 2015 10:10:56 +0200 Subject: [PATCH 38/70] Change c_zero to non-static as macos can't enqueue with static const ptr. --- libethash-cl/ethash_cl_miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index be17ba449..97443ce77 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -304,7 +304,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook }; std::queue pending; - static uint32_t const c_zero = 0; + uint32_t const c_zero = 0; // update header constant buffer m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); From e37ddf8eac99eebcf8b48f446665418c0e3315f3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 20 May 2015 11:45:39 +0200 Subject: [PATCH 39/70] bug fix --- mix/CodeModel.cpp | 8 +++---- mix/qml/CodeEditorView.qml | 2 +- mix/qml/StateListModel.qml | 1 + mix/qml/WebCodeEditor.qml | 26 +++------------------ mix/qml/html/cm/errorannotation.js | 3 --- mix/qml/html/codeeditor.js | 37 +++++++++++++++--------------- 6 files changed, 27 insertions(+), 50 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 9875ee1aa..f10b33408 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -331,11 +331,11 @@ QVariantMap CodeModel::resolveCompilationErrorLocation(CompilerStack const& _com { std::tuple pos = _compiler.positionFromSourceLocation(_location); QVariantMap startError; - startError.insert("line", std::get<0>(pos) - 1); - startError.insert("column", std::get<1>(pos) - 1); + startError.insert("line", std::get<0>(pos) > 1 ? (std::get<0>(pos) - 1) : 1); + startError.insert("column", std::get<1>(pos) > 1 ? (std::get<1>(pos) - 1) : 1); QVariantMap endError; - endError.insert("line", std::get<2>(pos) - 1); - endError.insert("column", std::get<3>(pos) - 1); + endError.insert("line", std::get<2>(pos) > 1 ? (std::get<2>(pos) - 1) : 1); + endError.insert("column", std::get<3>(pos) > 1 ? (std::get<3>(pos) - 1) : 1); QVariantMap error; error.insert("start", startError); error.insert("end", endError); diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 1a5e3f0f8..4f5516264 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -74,8 +74,8 @@ Item { }); } editor.document = document; - editor.setSourceName(document.documentId); editor.setFontSize(editorSettings.fontSize); + editor.sourceName = document.documentId; editor.setText(data, document.syntaxMode); editor.changeGeneration(); } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index f21c93199..a94188a23 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -225,6 +225,7 @@ Item { var ctorTr = defaultTransactionItem(); ctorTr.functionId = c; ctorTr.contractId = c; + ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; ctorTr.sender = item.accounts[0].secret; item.transactions.push(ctorTr); } diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index babb200e8..b188cacd6 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -83,13 +83,6 @@ Item { editorBrowser.runJavaScript("setFontSize(" + size + ")", function(result) {}); } - function setSourceName(_sourceName) - { - sourceName = _sourceName; - if (initialized && editorBrowser) - editorBrowser.runJavaScript("setSourceName('" + sourceName + "')", function(result) {}); - } - Clipboard { id: clipboard @@ -148,29 +141,16 @@ Item { { if (!editorBrowser || !error) return; - - var lineError = firstLocation.start.line + 1; - var errorOrigin = "source error in " + firstLocation.contractName + " line " + lineError - var secondErrorDetail = " Secondary sources: "; - for (var k in secondLocations) - { - lineError = secondLocations[k].start.line + 1; - secondErrorDetail += secondLocations[k].contractName + " line " + lineError + " - "; - displayErrorAnnotations(secondLocations[k], errorOrigin, "second"); - } var detail = error.split('\n')[0]; var reg = detail.match(/:\d+:\d+:/g); if (reg !== null) detail = detail.replace(reg[0], ""); - if (secondLocations.length > 0) - detail += secondErrorDetail; - displayErrorAnnotations(firstLocation, detail, "first"); + displayErrorAnnotations(detail, firstLocation, secondLocations); } - function displayErrorAnnotations(location, detail, type) + function displayErrorAnnotations(detail, location, secondaryErrors) { - if (location.source === parent.sourceName) - editorBrowser.runJavaScript("compilationError('" + JSON.stringify(location) + "', '" + detail + "', '" + type + "')", function(result){}); + editorBrowser.runJavaScript("compilationError('" + sourceName + "', '" + JSON.stringify(location) + "', '" + detail + "', '" + JSON.stringify(secondaryErrors) + "')", function(result){}); } Timer diff --git a/mix/qml/html/cm/errorannotation.js b/mix/qml/html/cm/errorannotation.js index a8cdb6fe6..33837ed37 100644 --- a/mix/qml/html/cm/errorannotation.js +++ b/mix/qml/html/cm/errorannotation.js @@ -44,6 +44,3 @@ ErrorAnnotation.prototype.destroy = function() if (this.errorMark) this.errorMark.clear(); } - - - diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index fd5d88df0..c85a87597 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -8,7 +8,6 @@ var editor = CodeMirror(document.body, { styleSelectedText: true }); var ternServer; -var sourceName = ""; editor.setOption("theme", "inkpot"); editor.setOption("indentUnit", 4); @@ -160,35 +159,40 @@ showWarning = function(content) var annotations = []; var compilationCompleteBool = true; -compilationError = function(location, error, type) +compilationError = function(currentSourceName, location, error, secondaryErrors) { compilationCompleteBool = false; if (compilationCompleteBool) return; + clearAnnotations(); location = JSON.parse(location); - if (location.start.line) - ensureAnnotation(location, error, type); + if (location.source === currentSourceName) + ensureAnnotation(location, error, "first"); + var lineError = location.start.line + 1; + var errorOrigin = "Source " + location.contractName + " line " + lineError; + secondaryErrors = JSON.parse(secondaryErrors); + for(var i in secondaryErrors) + { + if (secondaryErrors[i].source === currentSourceName) + ensureAnnotation(secondaryErrors[i], errorOrigin, "second"); + } } ensureAnnotation = function(location, error, type) { - for (var k in annotations) - { - if (annotations[k].annotation.location.start.line === location.start.line) - { - annotations[k].annotation.destroy(); - annotations.splice(k, 1); - break; - } - } annotations.push({ "type": type, "annotation": new ErrorAnnotation(editor, location, error)}); } -compilationComplete = function() +clearAnnotations = function() { for (var k in annotations) annotations[k].annotation.destroy(); annotations.length = 0; +} + +compilationComplete = function() +{ + clearAnnotations(); compilationCompleteBool = true; } @@ -204,10 +208,5 @@ setFontSize = function(size) editor.refresh(); } -setSourceName = function(_sourceName) -{ - sourceName = _sourceName; -} - editor.setOption("extraKeys", extraKeys); From 8b7ec057f4d01e9e42ee2ce31f8abf5fcd8f3be1 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 20 May 2015 13:20:34 +0200 Subject: [PATCH 40/70] remove eth_solidity dependency for statetests --- test/libethereum/state.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index fe0f10ca3..ed5cf14ac 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -176,12 +176,10 @@ BOOST_AUTO_TEST_CASE(stMemoryStressTest) dev::test::executeTests("stMemoryStressTest", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); } -#if ETH_SOLIDITY BOOST_AUTO_TEST_CASE(stSolidityTest) { dev::test::executeTests("stSolidityTest", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); } -#endif BOOST_AUTO_TEST_CASE(stMemoryTest) { From 68c9eb2937667a3f2b6d157d40be9f3864d222d3 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 20 May 2015 15:32:52 +0200 Subject: [PATCH 41/70] fix whitespace --- libethash-cl/ethash_cl_miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 97443ce77..93ce9ab22 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -304,7 +304,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook }; std::queue pending; - uint32_t const c_zero = 0; + uint32_t const c_zero = 0; // update header constant buffer m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); From 8c118dc6b76b1a1f3e8d2fdd534cf21173f3a4f9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 20 May 2015 17:21:48 +0200 Subject: [PATCH 42/70] Bugfix concerning receive address for CALLCODE. --- libevm/VM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 27650e3ad..ff771d21c 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -635,7 +635,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) if (m_stack[m_stack.size() - 3] > 0) callParams->gas += c_callStipend; m_stack.pop_back(); - callParams->receiveAddress = asAddress(m_stack.back()); + callParams->codeAddress = asAddress(m_stack.back()); m_stack.pop_back(); callParams->value = m_stack.back(); m_stack.pop_back(); @@ -653,7 +653,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { callParams->onOp = _onOp; callParams->senderAddress = _ext.myAddress; - callParams->codeAddress = inst == Instruction::CALL ? callParams->receiveAddress : callParams->senderAddress; + callParams->receiveAddress = inst == Instruction::CALL ? callParams->codeAddress : callParams->senderAddress; callParams->data = bytesConstRef(m_temp.data() + inOff, inSize); callParams->out = bytesRef(m_temp.data() + outOff, outSize); m_stack.push_back(_ext.call(*callParams)); From c16ee526d527e41e5d6e1160c728ab1290e4d73d Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 17:57:41 +0200 Subject: [PATCH 43/70] added tests to check references to struct type. --- test/libsolidity/SolidityEndToEndTest.cpp | 87 +++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 90ce20d26..f9870a9ad 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4023,9 +4023,96 @@ BOOST_AUTO_TEST_CASE(overwriting_inheritance) BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(6)); } +BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) +{ + char const* sourceCode = R"( + contract test { + struct testStruct + { + uint m_value; + } + testStruct data1; + testStruct data2; + testStruct data3; + function test() + { + data1.m_value = 2; + } + function assign() returns (uint ret_local, uint ret_global, uint ret_global3, uint ret_global1) + { + testStruct x = data1; //x is a reference data1..m_value == 2 as well as x.m_value = 2 + data2 = data1; // should copy data. data2.m_value == 2 + + ret_local = x.m_value; // = 2 + ret_global = data2.m_value; // = 2 + + x.m_value = 3; + data3 = x; //should copy the data. data3.m_value == 3 + ret_global3 = data3.m_value; // = 3 + ret_global1 = data1.m_value; // =3 + } + } + )"; + compileAndRun(sourceCode, 0, "test"); + BOOST_CHECK(callContractFunction("assign()") == encodeArgs(2, 2, 3, 3)); +} + +BOOST_AUTO_TEST_CASE(struct_delete_member) +{ + char const* sourceCode = R"( + contract test { + struct testStruct + { + uint m_value; + } + testStruct data1; + function test() + { + data1.m_value = 2; + } + function deleteMember() returns (uint ret_value) + { + testStruct x = data1; //should not copy the data. data1.m_value == 2 but x.m_value = 0 + x.m_value = 4; + delete x.m_value; + ret_value = x.m_value; + } + } + )"; + compileAndRun(sourceCode, 0, "test"); + auto res = callContractFunction("deleteMember()"); + BOOST_CHECK(callContractFunction("deleteMember()") == encodeArgs(0)); +} + +BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) +{ + char const* sourceCode = R"( + contract test { + struct testStruct + { + uint m_value; + } + mapping (uint => testStruct) campaigns; + + function test() + { + campaigns[0].m_value = 2; + } + function deleteIt() returns (uint) + { + delete campaigns[0]; + return campaigns[0].m_value; + } + } + )"; + compileAndRun(sourceCode, 0, "test"); + auto res = callContractFunction("deleteIt()"); + BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); +} BOOST_AUTO_TEST_SUITE_END() } } } // end namespaces + From 4268174af782c03ea828b76e00644ca9ba3e8ed3 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 18:05:51 +0200 Subject: [PATCH 44/70] Update SolidityEndToEndTest.cpp --- test/libsolidity/SolidityEndToEndTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f9870a9ad..c900fff4c 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4115,4 +4115,3 @@ BOOST_AUTO_TEST_SUITE_END() } } } // end namespaces - From f3b89a9677ed7b2df1c9a1f5e16e112f75f18a57 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 18:35:05 +0200 Subject: [PATCH 45/70] style fix --- test/libsolidity/SolidityEndToEndTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index c900fff4c..6b7007a29 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4040,7 +4040,7 @@ BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) } function assign() returns (uint ret_local, uint ret_global, uint ret_global3, uint ret_global1) { - testStruct x = data1; //x is a reference data1..m_value == 2 as well as x.m_value = 2 + testStruct x = data1; //x is a reference data1.m_value == 2 as well as x.m_value = 2 data2 = data1; // should copy data. data2.m_value == 2 ret_local = x.m_value; // = 2 @@ -4049,7 +4049,7 @@ BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) x.m_value = 3; data3 = x; //should copy the data. data3.m_value == 3 ret_global3 = data3.m_value; // = 3 - ret_global1 = data1.m_value; // =3 + ret_global1 = data1.m_value; // = 3 } } )"; From 7c35547631e456a4594e41ec229f3fe9f6e97201 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 18:37:09 +0200 Subject: [PATCH 46/70] Update InterfaceHandler.cpp --- libsolidity/InterfaceHandler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 9124d210f..9a2acd5ba 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -108,8 +108,7 @@ unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition { string ret = "contract " + _contractDef.getName() + "{"; - auto populateParameters = [](vector const& _paramNames, - vector const& _paramTypes) + auto populateParameters = [](vector const& _paramNames, vector const& _paramTypes) { string r = ""; solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match"); From 050883805b68bb495583b87b51378d4b28943e0d Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 18:38:52 +0200 Subject: [PATCH 47/70] Update SolidityEndToEndTest.cpp --- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 6b7007a29..88a3613ad 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4049,7 +4049,7 @@ BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) x.m_value = 3; data3 = x; //should copy the data. data3.m_value == 3 ret_global3 = data3.m_value; // = 3 - ret_global1 = data1.m_value; // = 3 + ret_global1 = data1.m_value; // = 3. Changed due to the assignment to x.m_value } } )"; From 378341ce6026db3bf64341a7ad9d409904af8f85 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 18:40:00 +0200 Subject: [PATCH 48/70] Update SolidityEndToEndTest.cpp --- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 88a3613ad..503615a5a 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4075,7 +4075,7 @@ BOOST_AUTO_TEST_CASE(struct_delete_member) testStruct x = data1; //should not copy the data. data1.m_value == 2 but x.m_value = 0 x.m_value = 4; delete x.m_value; - ret_value = x.m_value; + ret_value = data1.m_value; } } )"; From 27654ae52c54eb9419d843fb2025a01adef0fc33 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 19:22:16 +0200 Subject: [PATCH 49/70] Scrypt support --- CMakeLists.txt | 1 + exp/main.cpp | 19 +- libdevcrypto/CMakeLists.txt | 1 + libdevcrypto/Common.cpp | 8 + libdevcrypto/Common.h | 3 + libdevcrypto/SecretStore.cpp | 5 + libscrypt/CMakeLists.txt | 24 ++ libscrypt/LICENSE | 9 + libscrypt/b64.c | 313 ++++++++++++++++++++ libscrypt/b64.h | 10 + libscrypt/crypto-mcf.c | 73 +++++ libscrypt/crypto-scrypt-saltgen.c | 48 ++++ libscrypt/crypto_scrypt-check.c | 100 +++++++ libscrypt/crypto_scrypt-hash.c | 44 +++ libscrypt/crypto_scrypt-hexconvert.c | 35 +++ libscrypt/crypto_scrypt-hexconvert.h | 9 + libscrypt/crypto_scrypt-nosse.c | 342 ++++++++++++++++++++++ libscrypt/libscrypt.h | 67 +++++ libscrypt/libscrypt.version | 8 + libscrypt/sha256.c | 411 +++++++++++++++++++++++++++ libscrypt/sha256.h | 70 +++++ libscrypt/slowequals.c | 26 ++ libscrypt/slowequals.h | 5 + libscrypt/sysendian.h | 144 ++++++++++ 24 files changed, 1771 insertions(+), 4 deletions(-) create mode 100644 libscrypt/CMakeLists.txt create mode 100644 libscrypt/LICENSE create mode 100644 libscrypt/b64.c create mode 100644 libscrypt/b64.h create mode 100644 libscrypt/crypto-mcf.c create mode 100644 libscrypt/crypto-scrypt-saltgen.c create mode 100644 libscrypt/crypto_scrypt-check.c create mode 100644 libscrypt/crypto_scrypt-hash.c create mode 100644 libscrypt/crypto_scrypt-hexconvert.c create mode 100644 libscrypt/crypto_scrypt-hexconvert.h create mode 100644 libscrypt/crypto_scrypt-nosse.c create mode 100644 libscrypt/libscrypt.h create mode 100644 libscrypt/libscrypt.version create mode 100644 libscrypt/sha256.c create mode 100644 libscrypt/sha256.h create mode 100644 libscrypt/slowequals.c create mode 100644 libscrypt/slowequals.h create mode 100644 libscrypt/sysendian.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aafdad099..8239e20a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,6 +364,7 @@ if (JSCONSOLE) endif () add_subdirectory(secp256k1) +add_subdirectory(libscrypt) add_subdirectory(libdevcrypto) if (GENERAL) diff --git a/exp/main.cpp b/exp/main.cpp index 47efe576a..5162d915b 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -36,7 +36,6 @@ #include #include #include -/* #include #include #include @@ -57,17 +56,29 @@ #include #include #include -#include */ +#include using namespace std; using namespace dev; -/*using namespace dev::eth; +using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; -*/ + #if 1 +int main() +{ + cdebug << pbkdf2("password", asBytes("salt"), 1, 32); + cdebug << pbkdf2("password", asBytes("salt"), 1, 16); + cdebug << pbkdf2("password", asBytes("salt"), 2, 16); + cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); + return 0; +} + + +#elif 0 + int main() { cdebug << "EXP"; diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt index 295dd257a..7df1149b0 100644 --- a/libdevcrypto/CMakeLists.txt +++ b/libdevcrypto/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) +target_link_libraries(${EXECUTABLE} scrypt) target_link_libraries(${EXECUTABLE} devcore) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 87e258573..2a3561314 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -180,6 +181,13 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, return ret; } +bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) +{ + bytes ret(_dkLen); + libscrypt_scrypt((uint8_t const*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _n, _r, _p, ret.data(), ret.size()); + return ret; +} + KeyPair KeyPair::create() { static boost::thread_specific_ptr s_eng; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 6464c7ede..a0f894a25 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -123,6 +123,9 @@ bool verify(Public const& _k, Signature const& _s, h256 const& _hash); /// Derive key via PBKDF2. bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); +/// Derive key via Scrypt. +bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); + /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// Actually stores a tuplet of secret, public and address (the right 160-bits of the public). diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 0416aa9f4..7bc870bcf 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -188,6 +188,11 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) bytes salt = fromHex(params["salt"].get_str()); derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int()); } + else if (o["kdf"].get_str() == "scrypt") + { + auto p = o["kdfparams"].get_obj(); + derivedKey = scrypt(_pass, fromHex(p["salt"].get_str()), p["n"].get_int(), p["p"].get_int(), p["r"].get_int(), p["dklen"].get_int()); + } else { cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; diff --git a/libscrypt/CMakeLists.txt b/libscrypt/CMakeLists.txt new file mode 100644 index 000000000..8543244c5 --- /dev/null +++ b/libscrypt/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_policy(SET CMP0015 NEW) +# this policy was introduced in cmake 3.0 +# remove if, once 3.0 will be used on unix +if (${CMAKE_MAJOR_VERSION} GREATER 2) + # old policy do not use MACOSX_RPATH + cmake_policy(SET CMP0042 OLD) +endif() +set(CMAKE_AUTOMOC OFF) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) + +set(EXECUTABLE scrypt) + +file(GLOB HEADERS "*.h") + +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libscrypt/LICENSE b/libscrypt/LICENSE new file mode 100644 index 000000000..46a743175 --- /dev/null +++ b/libscrypt/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) 2013, Joshua Small + All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/libscrypt/b64.c b/libscrypt/b64.c new file mode 100644 index 000000000..b797dd0d9 --- /dev/null +++ b/libscrypt/b64.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Base64 encode/decode functions from OpenBSD (src/lib/libc/net/base64.c). + */ +#include +#include +#include +#include +#include + +#include "b64.h" + + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. +*/ + +int +libscrypt_b64_encode(src, srclength, target, targsize) + unsigned char const *src; + size_t srclength; + char *target; + size_t targsize; +{ + size_t datalength = 0; + unsigned char input[3]; + unsigned char output[4]; + unsigned int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (int)(datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +libscrypt_b64_decode(src, target, targsize) + char const *src; + unsigned char *target; + size_t targsize; +{ + int state, ch; + unsigned int tarindex; + unsigned char nextbyte; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = (unsigned char)*src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + nextbyte = ((pos - Base64) & 0x0f) << 4; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + nextbyte = ((pos - Base64) & 0x03) << 6; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = (unsigned char)*src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = (unsigned char)*src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && tarindex < targsize && + target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/libscrypt/b64.h b/libscrypt/b64.h new file mode 100644 index 000000000..2e271eb5b --- /dev/null +++ b/libscrypt/b64.h @@ -0,0 +1,10 @@ + +/* BASE64 libraries used internally - should not need to be packaged */ + +#define b64_encode_len(A) ((A+2)/3 * 4 + 1) +#define b64_decode_len(A) (A / 4 * 3 + 2) + +int libscrypt_b64_encode(unsigned char const *src, size_t srclength, + /*@out@*/ char *target, size_t targetsize); +int libscrypt_b64_decode(char const *src, /*@out@*/ unsigned char *target, + size_t targetsize); diff --git a/libscrypt/crypto-mcf.c b/libscrypt/crypto-mcf.c new file mode 100644 index 000000000..8ad3eb826 --- /dev/null +++ b/libscrypt/crypto-mcf.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ +#include +#endif + +#include "libscrypt.h" + +/* ilog2 for powers of two */ +static uint32_t scrypt_ilog2(uint32_t n) +{ +#ifndef S_SPLINT_S + + /* Check for a valid power of two */ + if (n < 2 || (n & (n - 1))) + return -1; +#endif + uint32_t t = 1; + while (((uint32_t)1 << t) < n) + { + if(t > SCRYPT_SAFE_N) + return (uint32_t) -1; /* Check for insanity */ + t++; + } + + return t; +} + +#ifdef _MSC_VER + #define SNPRINTF _snprintf +#else + #define SNPRINTF snprintf +#endif + +int libscrypt_mcf(uint32_t N, uint32_t r, uint32_t p, const char *salt, + const char *hash, char *mcf) +{ + + uint32_t t, params; + int s; + + if(!mcf || !hash) + return 0; + /* Although larger values of r, p are valid in scrypt, this mcf format + * limits to 8 bits. If your number is larger, current computers will + * struggle + */ + if(r > (uint8_t)(-1) || p > (uint8_t)(-1)) + return 0; + + t = scrypt_ilog2(N); + if (t < 1) + return 0; + + params = (r << 8) + p; + params += (uint32_t)t << 16; + + /* Using snprintf - not checking for overflows. We've already + * determined that mcf should be defined as at least SCRYPT_MCF_LEN + * in length + */ + s = SNPRINTF(mcf, SCRYPT_MCF_LEN, SCRYPT_MCF_ID "$%06x$%s$%s", (unsigned int)params, salt, hash); + if (s > SCRYPT_MCF_LEN) + return 0; + + return 1; +} diff --git a/libscrypt/crypto-scrypt-saltgen.c b/libscrypt/crypto-scrypt-saltgen.c new file mode 100644 index 000000000..a0e29988c --- /dev/null +++ b/libscrypt/crypto-scrypt-saltgen.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +#ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ +#include +#endif + +#define RNGDEV "/dev/urandom" + +int libscrypt_salt_gen(uint8_t *salt, size_t len) +{ + unsigned char buf[len]; + size_t data_read = 0; + int urandom = open(RNGDEV, O_RDONLY); + + if (urandom < 0) + { + return -1; + } + + while (data_read < len) { + ssize_t result = read(urandom, buf + data_read, len - data_read); + + if (result < 0) + { + if (errno == EINTR || errno == EAGAIN) { + continue; + } + + else { + (void)close(urandom); + return -1; + } + } + + data_read += result; + } + + /* Failures on close() shouldn't occur with O_RDONLY */ + (void)close(urandom); + + memcpy(salt, buf, len); + + return 0; +} diff --git a/libscrypt/crypto_scrypt-check.c b/libscrypt/crypto_scrypt-check.c new file mode 100644 index 000000000..99477ffe9 --- /dev/null +++ b/libscrypt/crypto_scrypt-check.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include + +#include "b64.h" +#include "slowequals.h" +#include "libscrypt.h" + +#ifdef _WIN32 +/* On windows, strtok uses a thread-local static variable in strtok to + * make strtok thread-safe. It also neglects to provide a strtok_r. */ +#define strtok_r(str, val, saveptr) strtok((str), (val)) +#endif + +int libscrypt_check(char *mcf, const char *password) +{ + /* Return values: + * <0 error + * == 0 password incorrect + * >0 correct password + */ + +#ifndef _WIN32 + char *saveptr = NULL; +#endif + uint32_t params; + uint64_t N; + uint8_t r, p; + int retval; + uint8_t hashbuf[64]; + char outbuf[128]; + uint8_t salt[32]; + char *tok; + + if(memcmp(mcf, SCRYPT_MCF_ID, 3) != 0) + { + /* Only version 0 supported */ + return -1; + } + + tok = strtok_r(mcf, "$", &saveptr); + if ( !tok ) + return -1; + + tok = strtok_r(NULL, "$", &saveptr); + + if ( !tok ) + return -1; + + params = (uint32_t)strtoul(tok, NULL, 16); + if ( params == 0 ) + return -1; + + tok = strtok_r(NULL, "$", &saveptr); + + if ( !tok ) + return -1; + + p = params & 0xff; + r = (params >> 8) & 0xff; + N = params >> 16; + + if (N > SCRYPT_SAFE_N) + return -1; + + N = (uint64_t)1 << N; + + /* Useful debugging: + printf("We've obtained salt 'N' r p of '%s' %d %d %d\n", tok, N,r,p); + */ + + memset(salt, 0, sizeof(salt)); /* Keeps splint happy */ + retval = libscrypt_b64_decode(tok, (unsigned char*)salt, sizeof(salt)); + if (retval < 1) + return -1; + + retval = libscrypt_scrypt((uint8_t*)password, strlen(password), salt, + (uint32_t)retval, N, r, p, hashbuf, sizeof(hashbuf)); + + if (retval != 0) + return -1; + + retval = libscrypt_b64_encode((unsigned char*)hashbuf, sizeof(hashbuf), + outbuf, sizeof(outbuf)); + + if (retval == 0) + return -1; + + tok = strtok_r(NULL, "$", &saveptr); + + if ( !tok ) + return -1; + + if(slow_equals(tok, outbuf) == 0) + return 0; + + return 1; /* This is the "else" condition */ +} + diff --git a/libscrypt/crypto_scrypt-hash.c b/libscrypt/crypto_scrypt-hash.c new file mode 100644 index 000000000..4b41007db --- /dev/null +++ b/libscrypt/crypto_scrypt-hash.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +#include "b64.h" +#include "libscrypt.h" + +int libscrypt_hash(char *dst, const char *passphrase, uint32_t N, uint8_t r, + uint8_t p) +{ + + int retval; + uint8_t salt[SCRYPT_SALT_LEN]; + uint8_t hashbuf[SCRYPT_HASH_LEN]; + char outbuf[256]; + char saltbuf[256]; + + if(libscrypt_salt_gen(salt, SCRYPT_SALT_LEN) == -1) + { + return 0; + } + + retval = libscrypt_scrypt((const uint8_t*)passphrase, strlen(passphrase), + (uint8_t*)salt, SCRYPT_SALT_LEN, N, r, p, hashbuf, sizeof(hashbuf)); + if(retval == -1) + return 0; + + retval = libscrypt_b64_encode((unsigned char*)hashbuf, sizeof(hashbuf), + outbuf, sizeof(outbuf)); + if(retval == -1) + return 0; + + retval = libscrypt_b64_encode((unsigned char *)salt, sizeof(salt), + saltbuf, sizeof(saltbuf)); + if(retval == -1) + return 0; + + retval = libscrypt_mcf(N, r, p, saltbuf, outbuf, dst); + if(retval != 1) + return 0; + + return 1; +} diff --git a/libscrypt/crypto_scrypt-hexconvert.c b/libscrypt/crypto_scrypt-hexconvert.c new file mode 100644 index 000000000..3df12a023 --- /dev/null +++ b/libscrypt/crypto_scrypt-hexconvert.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +/* The hexconvert function is only used to test reference vectors against + * known answers. The contents of this file are therefore a component + * to assist with test harnesses only + */ + +int libscrypt_hexconvert(uint8_t *buf, size_t s, char *outbuf, size_t obs) +{ + + size_t i; + int len = 0; + + if (!buf || s < 1 || obs < (s * 2 + 1)) + return 0; + + memset(outbuf, 0, obs); + + + for(i=0; i<=(s-1); i++) + { + /* snprintf(outbuf, s,"%s...", outbuf....) has undefined results + * and can't be used. Using offests like this makes snprintf + * nontrivial. we therefore have use inescure sprintf() and + * lengths checked elsewhere (start of function) */ + /*@ -bufferoverflowhigh @*/ + len += sprintf(outbuf+len, "%02x", (unsigned int) buf[i]); + } + + return 1; +} + diff --git a/libscrypt/crypto_scrypt-hexconvert.h b/libscrypt/crypto_scrypt-hexconvert.h new file mode 100644 index 000000000..8175b24f1 --- /dev/null +++ b/libscrypt/crypto_scrypt-hexconvert.h @@ -0,0 +1,9 @@ + +#include + +/** + * Converts a binary string to a hex representation of that string + * outbuf must have size of at least buf * 2 + 1. + */ +int libscrypt_hexconvert(const uint8_t *buf, size_t s, char *outbuf, + size_t obs); diff --git a/libscrypt/crypto_scrypt-nosse.c b/libscrypt/crypto_scrypt-nosse.c new file mode 100644 index 000000000..12c860f2d --- /dev/null +++ b/libscrypt/crypto_scrypt-nosse.c @@ -0,0 +1,342 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include + +#include "sha256.h" +#include "sysendian.h" + +#include "libscrypt.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error + */ +int +libscrypt_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (r == 0 || p == 0) { + errno = EINVAL; + goto err0; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + libscrypt_PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + libscrypt_PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/libscrypt/libscrypt.h b/libscrypt/libscrypt.h new file mode 100644 index 000000000..b7141f5f5 --- /dev/null +++ b/libscrypt/libscrypt.h @@ -0,0 +1,67 @@ +/*- + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * libscrypt_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * password; duh + * N: CPU AND RAM cost (first modifier) + * r: RAM Cost + * p: CPU cost (parallelisation) + * In short, N is your main performance modifier. Values of r = 8, p = 1 are + * standard unless you want to modify the CPU/RAM ratio. + * Return 0 on success; or -1 on error. + */ +int libscrypt_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint32_t, uint32_t, /*@out@*/ uint8_t *, size_t); + +/* Converts a series of input parameters to a MCF form for storage */ +int libscrypt_mcf(uint32_t N, uint32_t r, uint32_t p, const char *salt, + const char *hash, char *mcf); + +#ifndef _MSC_VER +/* Generates a salt. Uses /dev/urandom/ + */ +int libscrypt_salt_gen(/*@out@*/ uint8_t *rand, size_t len); + +/* Creates a hash of a passphrase using a randomly generated salt */ +/* Returns >0 on success, or 0 for fail */ +int libscrypt_hash(char *dst, const char* passphrase, uint32_t N, uint8_t r, + uint8_t p); +#endif + +/* Checks a given MCF against a password */ +int libscrypt_check(char *mcf, const char *password); + +#ifdef __cplusplus +} +#endif + +/* Sane default values */ +#define SCRYPT_HASH_LEN 64 /* This can be user defined - + *but 64 is the reference size + */ +#define SCRYPT_SAFE_N 30 /* This is much higher than you want. It's just + * a blocker for insane defines + */ +#define SCRYPT_SALT_LEN 16 /* This is just a recommended size */ +#define SCRYPT_MCF_LEN 125 /* mcf is 120 byte + nul */ +#define SCRYPT_MCF_ID "$s1" +#define SCRYPT_N 16384 +#define SCRYPT_r 8 +#define SCRYPT_p 16 +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/libscrypt/libscrypt.version b/libscrypt/libscrypt.version new file mode 100644 index 000000000..9cc574db2 --- /dev/null +++ b/libscrypt/libscrypt.version @@ -0,0 +1,8 @@ +libscrypt { + global: libscrypt_check; +libscrypt_hash; +libscrypt_mcf; +libscrypt_salt_gen; +libscrypt_scrypt; + local: *; +}; diff --git a/libscrypt/sha256.c b/libscrypt/sha256.c new file mode 100644 index 000000000..279e3cf8d --- /dev/null +++ b/libscrypt/sha256.c @@ -0,0 +1,411 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "sysendian.h" + +#include "sha256.h" + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + libscrypt_SHA256_Update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + libscrypt_SHA256_Update(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +libscrypt_SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void +libscrypt_SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +libscrypt_SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +libscrypt_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + libscrypt_SHA256_Init(&ctx->ictx); + libscrypt_SHA256_Update(&ctx->ictx, K, Klen); + libscrypt_SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + libscrypt_SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + libscrypt_SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + libscrypt_SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + libscrypt_SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +libscrypt_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + libscrypt_SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +libscrypt_HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + libscrypt_SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + libscrypt_SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + libscrypt_SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +libscrypt_PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + libscrypt_HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + libscrypt_HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + libscrypt_HMAC_SHA256_Update(&hctx, ivec, 4); + libscrypt_HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + libscrypt_HMAC_SHA256_Init(&hctx, passwd, passwdlen); + libscrypt_HMAC_SHA256_Update(&hctx, U, 32); + libscrypt_HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} diff --git a/libscrypt/sha256.h b/libscrypt/sha256.h new file mode 100644 index 000000000..f7138b417 --- /dev/null +++ b/libscrypt/sha256.h @@ -0,0 +1,70 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include + +#include + +typedef struct libscrypt_SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX; + +typedef struct libscrypt_HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +void libscrypt_SHA256_Init(/*@out@*/ SHA256_CTX *); +void libscrypt_SHA256_Update(SHA256_CTX *, const void *, size_t); + +/* Original declaration: + * void SHA256_Final(unsigned char [32], SHA256_CTX *); +*/ +void libscrypt_SHA256_Final(/*@out@*/ unsigned char [], SHA256_CTX *); +void libscrypt_HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); +void libscrypt_HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); + +/* Original declaration: + * void HMAC_SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *); +*/ +void libscrypt_HMAC_SHA256_Final(unsigned char [], HMAC_SHA256_CTX *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void libscrypt_PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/libscrypt/slowequals.c b/libscrypt/slowequals.c new file mode 100644 index 000000000..48e488e4e --- /dev/null +++ b/libscrypt/slowequals.c @@ -0,0 +1,26 @@ +#include + +/* Implements a constant time version of strcmp() + * Will return 1 if a and b are equal, 0 if they are not */ +int slow_equals(const char* a, const char* b) +{ + size_t lena, lenb, diff, i; + lena = strlen(a); + lenb = strlen(b); + diff = strlen(a) ^ strlen(b); + + for(i=0; i we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include + +#else + +#include +#ifdef _MSC_VER + #define INLINE __inline +#else + #define INLINE inline +#endif + +static INLINE uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static INLINE void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static INLINE uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static INLINE void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static INLINE uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static INLINE void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static INLINE uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static INLINE void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ From e789f645eacd213c461277c787bd645c15e52ffd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 22:06:21 +0200 Subject: [PATCH 50/70] Ability to import version 1 keys. Possibly. --- alethzero/Main.ui | 8 ++- alethzero/MainWin.cpp | 27 +++++++++ alethzero/MainWin.h | 1 + libdevcrypto/SecretStore.cpp | 105 +++++++++++++++++++++++++++-------- libdevcrypto/SecretStore.h | 4 +- 5 files changed, 120 insertions(+), 25 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b5e22409d..f37f532a2 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -157,6 +157,7 @@ + @@ -1656,7 +1657,7 @@ font-size: 14pt &Enable Local Addresses - + true @@ -1745,6 +1746,11 @@ font-size: 14pt Co&nfirm Transactions + + + Import &Secret Key File... + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 07f48c0bc..4f1da1c1a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -813,6 +813,33 @@ void Main::on_importKey_triggered() } void Main::on_importKeyFile_triggered() +{ + QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); + h128 uuid = m_keyManager.store().importKey(s.toStdString()); + if (!uuid) + { + QMessageBox::warning(this, "Key File Invalid", "Could not find secret key definition. This is probably not an Web3 key file."); + return; + } + + QString info = QInputDialog::getText(this, "Import Key File", "Enter a description of this key to help you recognise it in the future."); + + QString pass; + for (Secret s; !s;) + { + s = Secret(m_keyManager.store().secret(uuid, [&](){ + pass = QInputDialog::getText(this, "Import Key File", "Enter the password for the key to complete the import.", QLineEdit::Password); + return pass.toStdString(); + }, false)); + if (!s && QMessageBox::question(this, "Import Key File", "The password you provided is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) + return; + } + + QString hint = QInputDialog::getText(this, "Import Key File", "Enter a hint for this password to help you remember it."); + m_keyManager.importExisting(uuid, info.toStdString(), pass.toStdString(), hint.toStdString()); +} + +void Main::on_claimPresale_triggered() { QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); try diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 9f2082dd0..fdf7a9a72 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -138,6 +138,7 @@ private slots: void on_killAccount_triggered(); void on_importKey_triggered(); void on_importKeyFile_triggered(); + void on_claimPresale_triggered(); void on_exportKey_triggered(); // Account pane diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 7bc870bcf..e422c32f8 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -22,6 +22,7 @@ #include "SecretStore.h" #include #include +#include #include #include #include @@ -42,10 +43,10 @@ SecretStore::~SecretStore() { } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass) const +bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); - if (rit != m_cached.end()) + if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); if (it == m_keys.end()) @@ -101,28 +102,71 @@ void SecretStore::save(std::string const& _keysPath) } } +static js::mValue upgraded(std::string const& _s) +{ + js::mValue v; + js::read_string(_s, v); + if (v.type() != js::obj_type) + return js::mValue(); + js::mObject ret = v.get_obj(); + unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0; + if (version == 1) + { + // upgrade to version 2 + js::mObject old; + swap(old, ret); + + ret["id"] = old["Id"]; + js::mObject c; + c["ciphertext"] = old["Crypto"].get_obj()["CipherText"]; + c["cipher"] = "aes-128-cbc"; + { + js::mObject cp; + cp["iv"] = old["Crypto"].get_obj()["IV"]; + c["cipherparams"] = cp; + } + c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"]; + { + js::mObject kp; + kp["salt"] = old["Crypto"].get_obj()["Salt"]; + for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj()) + if (i.first != "SaltLen") + kp[boost::to_lower_copy(i.first)] = i.second; + c["kdfparams"] = kp; + } + c["sillymac"] = old["Crypto"].get_obj()["MAC"]; + c["sillymacjson"] = _s; + ret["crypto"] = c; + version = 2; + } + if (version == 2) + return ret; + return js::mValue(); +} + void SecretStore::load(std::string const& _keysPath) { fs::path p(_keysPath); boost::filesystem::create_directories(p); - js::mValue v; for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) if (is_regular_file(it->path())) - { - cdebug << "Reading" << it->path(); - js::read_string(contentsString(it->path().string()), v); - if (v.type() == js::obj_type) - { - js::mObject o = v.get_obj(); - int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; - if (version == 2) - m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string()); - else - cwarn << "Cannot read key version" << version; - } -// else -// cwarn << "Invalid JSON in key file" << it->path().string(); - } + readKey(it->path().string(), true); +} + +h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) +{ + cdebug << "Reading" << _file; + js::mValue u = upgraded(contentsString(_file)); + if (u.type() == js::obj_type) + { + js::mObject& o = u.get_obj(); + auto uuid = fromUUID(o["id"].get_str()); + m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _deleteFile ? _file : string()); + return uuid; + } + else + cwarn << "Invalid JSON in key file" << _file; + return h128(); } std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass) @@ -202,13 +246,28 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) bytes cipherText = fromHex(o["ciphertext"].get_str()); // check MAC - h256 mac(o["mac"].get_str()); - h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); - if (mac != macExp) + if (o.count("mac")) { - cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + h256 mac(o["mac"].get_str()); + h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + if (mac != macExp) + { + cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); + return bytes(); + } } + else if (o.count("sillymac")) + { + h256 mac(o["sillymac"].get_str()); + h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + if (mac != macExp) + { + cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); + return bytes(); + } + } + else + cwarn << "No MAC. Proceeding anyway."; // decrypt if (o["cipher"].get_str() == "aes-128-cbc") diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 18c290c1f..171603053 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -36,7 +36,8 @@ public: SecretStore(); ~SecretStore(); - bytes secret(h128 const& _uuid, std::function const& _pass) const; + bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } h128 importSecret(bytes const& _s, std::string const& _pass); void kill(h128 const& _uuid); @@ -48,6 +49,7 @@ private: void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); static std::string encrypt(bytes const& _v, std::string const& _pass); static bytes decrypt(std::string const& _v, std::string const& _pass); + h128 readKey(std::string const& _file, bool _deleteFile); mutable std::unordered_map m_cached; std::unordered_map> m_keys; From b0117dcf575cae67518d37a841c34f0e5409d132 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 19:22:16 +0200 Subject: [PATCH 51/70] Scrypt support --- CMakeLists.txt | 1 + exp/main.cpp | 19 +- libdevcrypto/CMakeLists.txt | 1 + libdevcrypto/Common.cpp | 8 + libdevcrypto/Common.h | 3 + libdevcrypto/SecretStore.cpp | 5 + libscrypt/CMakeLists.txt | 24 ++ libscrypt/LICENSE | 9 + libscrypt/b64.c | 313 ++++++++++++++++++++ libscrypt/b64.h | 10 + libscrypt/crypto-mcf.c | 73 +++++ libscrypt/crypto-scrypt-saltgen.c | 48 ++++ libscrypt/crypto_scrypt-check.c | 100 +++++++ libscrypt/crypto_scrypt-hash.c | 44 +++ libscrypt/crypto_scrypt-hexconvert.c | 35 +++ libscrypt/crypto_scrypt-hexconvert.h | 9 + libscrypt/crypto_scrypt-nosse.c | 342 ++++++++++++++++++++++ libscrypt/libscrypt.h | 67 +++++ libscrypt/libscrypt.version | 8 + libscrypt/sha256.c | 411 +++++++++++++++++++++++++++ libscrypt/sha256.h | 70 +++++ libscrypt/slowequals.c | 26 ++ libscrypt/slowequals.h | 5 + libscrypt/sysendian.h | 144 ++++++++++ 24 files changed, 1771 insertions(+), 4 deletions(-) create mode 100644 libscrypt/CMakeLists.txt create mode 100644 libscrypt/LICENSE create mode 100644 libscrypt/b64.c create mode 100644 libscrypt/b64.h create mode 100644 libscrypt/crypto-mcf.c create mode 100644 libscrypt/crypto-scrypt-saltgen.c create mode 100644 libscrypt/crypto_scrypt-check.c create mode 100644 libscrypt/crypto_scrypt-hash.c create mode 100644 libscrypt/crypto_scrypt-hexconvert.c create mode 100644 libscrypt/crypto_scrypt-hexconvert.h create mode 100644 libscrypt/crypto_scrypt-nosse.c create mode 100644 libscrypt/libscrypt.h create mode 100644 libscrypt/libscrypt.version create mode 100644 libscrypt/sha256.c create mode 100644 libscrypt/sha256.h create mode 100644 libscrypt/slowequals.c create mode 100644 libscrypt/slowequals.h create mode 100644 libscrypt/sysendian.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aafdad099..8239e20a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,6 +364,7 @@ if (JSCONSOLE) endif () add_subdirectory(secp256k1) +add_subdirectory(libscrypt) add_subdirectory(libdevcrypto) if (GENERAL) diff --git a/exp/main.cpp b/exp/main.cpp index 47efe576a..5162d915b 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -36,7 +36,6 @@ #include #include #include -/* #include #include #include @@ -57,17 +56,29 @@ #include #include #include -#include */ +#include using namespace std; using namespace dev; -/*using namespace dev::eth; +using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; -*/ + #if 1 +int main() +{ + cdebug << pbkdf2("password", asBytes("salt"), 1, 32); + cdebug << pbkdf2("password", asBytes("salt"), 1, 16); + cdebug << pbkdf2("password", asBytes("salt"), 2, 16); + cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); + return 0; +} + + +#elif 0 + int main() { cdebug << "EXP"; diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt index 295dd257a..7df1149b0 100644 --- a/libdevcrypto/CMakeLists.txt +++ b/libdevcrypto/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) +target_link_libraries(${EXECUTABLE} scrypt) target_link_libraries(${EXECUTABLE} devcore) install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 87e258573..2a3561314 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -180,6 +181,13 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, return ret; } +bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) +{ + bytes ret(_dkLen); + libscrypt_scrypt((uint8_t const*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _n, _r, _p, ret.data(), ret.size()); + return ret; +} + KeyPair KeyPair::create() { static boost::thread_specific_ptr s_eng; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 6464c7ede..a0f894a25 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -123,6 +123,9 @@ bool verify(Public const& _k, Signature const& _s, h256 const& _hash); /// Derive key via PBKDF2. bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); +/// Derive key via Scrypt. +bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); + /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// Actually stores a tuplet of secret, public and address (the right 160-bits of the public). diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 0416aa9f4..7bc870bcf 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -188,6 +188,11 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) bytes salt = fromHex(params["salt"].get_str()); derivedKey = pbkdf2(_pass, salt, iterations, params["dklen"].get_int()); } + else if (o["kdf"].get_str() == "scrypt") + { + auto p = o["kdfparams"].get_obj(); + derivedKey = scrypt(_pass, fromHex(p["salt"].get_str()), p["n"].get_int(), p["p"].get_int(), p["r"].get_int(), p["dklen"].get_int()); + } else { cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; diff --git a/libscrypt/CMakeLists.txt b/libscrypt/CMakeLists.txt new file mode 100644 index 000000000..8543244c5 --- /dev/null +++ b/libscrypt/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_policy(SET CMP0015 NEW) +# this policy was introduced in cmake 3.0 +# remove if, once 3.0 will be used on unix +if (${CMAKE_MAJOR_VERSION} GREATER 2) + # old policy do not use MACOSX_RPATH + cmake_policy(SET CMP0042 OLD) +endif() +set(CMAKE_AUTOMOC OFF) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) + +set(EXECUTABLE scrypt) + +file(GLOB HEADERS "*.h") + +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libscrypt/LICENSE b/libscrypt/LICENSE new file mode 100644 index 000000000..46a743175 --- /dev/null +++ b/libscrypt/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) 2013, Joshua Small + All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/libscrypt/b64.c b/libscrypt/b64.c new file mode 100644 index 000000000..b797dd0d9 --- /dev/null +++ b/libscrypt/b64.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Base64 encode/decode functions from OpenBSD (src/lib/libc/net/base64.c). + */ +#include +#include +#include +#include +#include + +#include "b64.h" + + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. +*/ + +int +libscrypt_b64_encode(src, srclength, target, targsize) + unsigned char const *src; + size_t srclength; + char *target; + size_t targsize; +{ + size_t datalength = 0; + unsigned char input[3]; + unsigned char output[4]; + unsigned int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (int)(datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +libscrypt_b64_decode(src, target, targsize) + char const *src; + unsigned char *target; + size_t targsize; +{ + int state, ch; + unsigned int tarindex; + unsigned char nextbyte; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = (unsigned char)*src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + nextbyte = ((pos - Base64) & 0x0f) << 4; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + nextbyte = ((pos - Base64) & 0x03) << 6; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = (unsigned char)*src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = (unsigned char)*src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && tarindex < targsize && + target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/libscrypt/b64.h b/libscrypt/b64.h new file mode 100644 index 000000000..2e271eb5b --- /dev/null +++ b/libscrypt/b64.h @@ -0,0 +1,10 @@ + +/* BASE64 libraries used internally - should not need to be packaged */ + +#define b64_encode_len(A) ((A+2)/3 * 4 + 1) +#define b64_decode_len(A) (A / 4 * 3 + 2) + +int libscrypt_b64_encode(unsigned char const *src, size_t srclength, + /*@out@*/ char *target, size_t targetsize); +int libscrypt_b64_decode(char const *src, /*@out@*/ unsigned char *target, + size_t targetsize); diff --git a/libscrypt/crypto-mcf.c b/libscrypt/crypto-mcf.c new file mode 100644 index 000000000..8ad3eb826 --- /dev/null +++ b/libscrypt/crypto-mcf.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ +#include +#endif + +#include "libscrypt.h" + +/* ilog2 for powers of two */ +static uint32_t scrypt_ilog2(uint32_t n) +{ +#ifndef S_SPLINT_S + + /* Check for a valid power of two */ + if (n < 2 || (n & (n - 1))) + return -1; +#endif + uint32_t t = 1; + while (((uint32_t)1 << t) < n) + { + if(t > SCRYPT_SAFE_N) + return (uint32_t) -1; /* Check for insanity */ + t++; + } + + return t; +} + +#ifdef _MSC_VER + #define SNPRINTF _snprintf +#else + #define SNPRINTF snprintf +#endif + +int libscrypt_mcf(uint32_t N, uint32_t r, uint32_t p, const char *salt, + const char *hash, char *mcf) +{ + + uint32_t t, params; + int s; + + if(!mcf || !hash) + return 0; + /* Although larger values of r, p are valid in scrypt, this mcf format + * limits to 8 bits. If your number is larger, current computers will + * struggle + */ + if(r > (uint8_t)(-1) || p > (uint8_t)(-1)) + return 0; + + t = scrypt_ilog2(N); + if (t < 1) + return 0; + + params = (r << 8) + p; + params += (uint32_t)t << 16; + + /* Using snprintf - not checking for overflows. We've already + * determined that mcf should be defined as at least SCRYPT_MCF_LEN + * in length + */ + s = SNPRINTF(mcf, SCRYPT_MCF_LEN, SCRYPT_MCF_ID "$%06x$%s$%s", (unsigned int)params, salt, hash); + if (s > SCRYPT_MCF_LEN) + return 0; + + return 1; +} diff --git a/libscrypt/crypto-scrypt-saltgen.c b/libscrypt/crypto-scrypt-saltgen.c new file mode 100644 index 000000000..a0e29988c --- /dev/null +++ b/libscrypt/crypto-scrypt-saltgen.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +#ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ +#include +#endif + +#define RNGDEV "/dev/urandom" + +int libscrypt_salt_gen(uint8_t *salt, size_t len) +{ + unsigned char buf[len]; + size_t data_read = 0; + int urandom = open(RNGDEV, O_RDONLY); + + if (urandom < 0) + { + return -1; + } + + while (data_read < len) { + ssize_t result = read(urandom, buf + data_read, len - data_read); + + if (result < 0) + { + if (errno == EINTR || errno == EAGAIN) { + continue; + } + + else { + (void)close(urandom); + return -1; + } + } + + data_read += result; + } + + /* Failures on close() shouldn't occur with O_RDONLY */ + (void)close(urandom); + + memcpy(salt, buf, len); + + return 0; +} diff --git a/libscrypt/crypto_scrypt-check.c b/libscrypt/crypto_scrypt-check.c new file mode 100644 index 000000000..99477ffe9 --- /dev/null +++ b/libscrypt/crypto_scrypt-check.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include + +#include "b64.h" +#include "slowequals.h" +#include "libscrypt.h" + +#ifdef _WIN32 +/* On windows, strtok uses a thread-local static variable in strtok to + * make strtok thread-safe. It also neglects to provide a strtok_r. */ +#define strtok_r(str, val, saveptr) strtok((str), (val)) +#endif + +int libscrypt_check(char *mcf, const char *password) +{ + /* Return values: + * <0 error + * == 0 password incorrect + * >0 correct password + */ + +#ifndef _WIN32 + char *saveptr = NULL; +#endif + uint32_t params; + uint64_t N; + uint8_t r, p; + int retval; + uint8_t hashbuf[64]; + char outbuf[128]; + uint8_t salt[32]; + char *tok; + + if(memcmp(mcf, SCRYPT_MCF_ID, 3) != 0) + { + /* Only version 0 supported */ + return -1; + } + + tok = strtok_r(mcf, "$", &saveptr); + if ( !tok ) + return -1; + + tok = strtok_r(NULL, "$", &saveptr); + + if ( !tok ) + return -1; + + params = (uint32_t)strtoul(tok, NULL, 16); + if ( params == 0 ) + return -1; + + tok = strtok_r(NULL, "$", &saveptr); + + if ( !tok ) + return -1; + + p = params & 0xff; + r = (params >> 8) & 0xff; + N = params >> 16; + + if (N > SCRYPT_SAFE_N) + return -1; + + N = (uint64_t)1 << N; + + /* Useful debugging: + printf("We've obtained salt 'N' r p of '%s' %d %d %d\n", tok, N,r,p); + */ + + memset(salt, 0, sizeof(salt)); /* Keeps splint happy */ + retval = libscrypt_b64_decode(tok, (unsigned char*)salt, sizeof(salt)); + if (retval < 1) + return -1; + + retval = libscrypt_scrypt((uint8_t*)password, strlen(password), salt, + (uint32_t)retval, N, r, p, hashbuf, sizeof(hashbuf)); + + if (retval != 0) + return -1; + + retval = libscrypt_b64_encode((unsigned char*)hashbuf, sizeof(hashbuf), + outbuf, sizeof(outbuf)); + + if (retval == 0) + return -1; + + tok = strtok_r(NULL, "$", &saveptr); + + if ( !tok ) + return -1; + + if(slow_equals(tok, outbuf) == 0) + return 0; + + return 1; /* This is the "else" condition */ +} + diff --git a/libscrypt/crypto_scrypt-hash.c b/libscrypt/crypto_scrypt-hash.c new file mode 100644 index 000000000..4b41007db --- /dev/null +++ b/libscrypt/crypto_scrypt-hash.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +#include "b64.h" +#include "libscrypt.h" + +int libscrypt_hash(char *dst, const char *passphrase, uint32_t N, uint8_t r, + uint8_t p) +{ + + int retval; + uint8_t salt[SCRYPT_SALT_LEN]; + uint8_t hashbuf[SCRYPT_HASH_LEN]; + char outbuf[256]; + char saltbuf[256]; + + if(libscrypt_salt_gen(salt, SCRYPT_SALT_LEN) == -1) + { + return 0; + } + + retval = libscrypt_scrypt((const uint8_t*)passphrase, strlen(passphrase), + (uint8_t*)salt, SCRYPT_SALT_LEN, N, r, p, hashbuf, sizeof(hashbuf)); + if(retval == -1) + return 0; + + retval = libscrypt_b64_encode((unsigned char*)hashbuf, sizeof(hashbuf), + outbuf, sizeof(outbuf)); + if(retval == -1) + return 0; + + retval = libscrypt_b64_encode((unsigned char *)salt, sizeof(salt), + saltbuf, sizeof(saltbuf)); + if(retval == -1) + return 0; + + retval = libscrypt_mcf(N, r, p, saltbuf, outbuf, dst); + if(retval != 1) + return 0; + + return 1; +} diff --git a/libscrypt/crypto_scrypt-hexconvert.c b/libscrypt/crypto_scrypt-hexconvert.c new file mode 100644 index 000000000..3df12a023 --- /dev/null +++ b/libscrypt/crypto_scrypt-hexconvert.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +/* The hexconvert function is only used to test reference vectors against + * known answers. The contents of this file are therefore a component + * to assist with test harnesses only + */ + +int libscrypt_hexconvert(uint8_t *buf, size_t s, char *outbuf, size_t obs) +{ + + size_t i; + int len = 0; + + if (!buf || s < 1 || obs < (s * 2 + 1)) + return 0; + + memset(outbuf, 0, obs); + + + for(i=0; i<=(s-1); i++) + { + /* snprintf(outbuf, s,"%s...", outbuf....) has undefined results + * and can't be used. Using offests like this makes snprintf + * nontrivial. we therefore have use inescure sprintf() and + * lengths checked elsewhere (start of function) */ + /*@ -bufferoverflowhigh @*/ + len += sprintf(outbuf+len, "%02x", (unsigned int) buf[i]); + } + + return 1; +} + diff --git a/libscrypt/crypto_scrypt-hexconvert.h b/libscrypt/crypto_scrypt-hexconvert.h new file mode 100644 index 000000000..8175b24f1 --- /dev/null +++ b/libscrypt/crypto_scrypt-hexconvert.h @@ -0,0 +1,9 @@ + +#include + +/** + * Converts a binary string to a hex representation of that string + * outbuf must have size of at least buf * 2 + 1. + */ +int libscrypt_hexconvert(const uint8_t *buf, size_t s, char *outbuf, + size_t obs); diff --git a/libscrypt/crypto_scrypt-nosse.c b/libscrypt/crypto_scrypt-nosse.c new file mode 100644 index 000000000..12c860f2d --- /dev/null +++ b/libscrypt/crypto_scrypt-nosse.c @@ -0,0 +1,342 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include + +#include "sha256.h" +#include "sysendian.h" + +#include "libscrypt.h" + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error + */ +int +libscrypt_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (r == 0 || p == 0) { + errno = EINVAL; + goto err0; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#ifndef MAP_ANON + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#ifndef MAP_ANON + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#ifdef MAP_ANON + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + libscrypt_PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + libscrypt_PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#ifdef MAP_ANON + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} diff --git a/libscrypt/libscrypt.h b/libscrypt/libscrypt.h new file mode 100644 index 000000000..b7141f5f5 --- /dev/null +++ b/libscrypt/libscrypt.h @@ -0,0 +1,67 @@ +/*- + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * libscrypt_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * password; duh + * N: CPU AND RAM cost (first modifier) + * r: RAM Cost + * p: CPU cost (parallelisation) + * In short, N is your main performance modifier. Values of r = 8, p = 1 are + * standard unless you want to modify the CPU/RAM ratio. + * Return 0 on success; or -1 on error. + */ +int libscrypt_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint32_t, uint32_t, /*@out@*/ uint8_t *, size_t); + +/* Converts a series of input parameters to a MCF form for storage */ +int libscrypt_mcf(uint32_t N, uint32_t r, uint32_t p, const char *salt, + const char *hash, char *mcf); + +#ifndef _MSC_VER +/* Generates a salt. Uses /dev/urandom/ + */ +int libscrypt_salt_gen(/*@out@*/ uint8_t *rand, size_t len); + +/* Creates a hash of a passphrase using a randomly generated salt */ +/* Returns >0 on success, or 0 for fail */ +int libscrypt_hash(char *dst, const char* passphrase, uint32_t N, uint8_t r, + uint8_t p); +#endif + +/* Checks a given MCF against a password */ +int libscrypt_check(char *mcf, const char *password); + +#ifdef __cplusplus +} +#endif + +/* Sane default values */ +#define SCRYPT_HASH_LEN 64 /* This can be user defined - + *but 64 is the reference size + */ +#define SCRYPT_SAFE_N 30 /* This is much higher than you want. It's just + * a blocker for insane defines + */ +#define SCRYPT_SALT_LEN 16 /* This is just a recommended size */ +#define SCRYPT_MCF_LEN 125 /* mcf is 120 byte + nul */ +#define SCRYPT_MCF_ID "$s1" +#define SCRYPT_N 16384 +#define SCRYPT_r 8 +#define SCRYPT_p 16 +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/libscrypt/libscrypt.version b/libscrypt/libscrypt.version new file mode 100644 index 000000000..9cc574db2 --- /dev/null +++ b/libscrypt/libscrypt.version @@ -0,0 +1,8 @@ +libscrypt { + global: libscrypt_check; +libscrypt_hash; +libscrypt_mcf; +libscrypt_salt_gen; +libscrypt_scrypt; + local: *; +}; diff --git a/libscrypt/sha256.c b/libscrypt/sha256.c new file mode 100644 index 000000000..279e3cf8d --- /dev/null +++ b/libscrypt/sha256.c @@ -0,0 +1,411 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "sysendian.h" + +#include "sha256.h" + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + libscrypt_SHA256_Update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + libscrypt_SHA256_Update(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +libscrypt_SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void +libscrypt_SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +libscrypt_SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +libscrypt_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + libscrypt_SHA256_Init(&ctx->ictx); + libscrypt_SHA256_Update(&ctx->ictx, K, Klen); + libscrypt_SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + libscrypt_SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + libscrypt_SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + libscrypt_SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + libscrypt_SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +libscrypt_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + libscrypt_SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +libscrypt_HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + libscrypt_SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + libscrypt_SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + libscrypt_SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +libscrypt_PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + libscrypt_HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + libscrypt_HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + libscrypt_HMAC_SHA256_Update(&hctx, ivec, 4); + libscrypt_HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + libscrypt_HMAC_SHA256_Init(&hctx, passwd, passwdlen); + libscrypt_HMAC_SHA256_Update(&hctx, U, 32); + libscrypt_HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} diff --git a/libscrypt/sha256.h b/libscrypt/sha256.h new file mode 100644 index 000000000..f7138b417 --- /dev/null +++ b/libscrypt/sha256.h @@ -0,0 +1,70 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include + +#include + +typedef struct libscrypt_SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX; + +typedef struct libscrypt_HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +void libscrypt_SHA256_Init(/*@out@*/ SHA256_CTX *); +void libscrypt_SHA256_Update(SHA256_CTX *, const void *, size_t); + +/* Original declaration: + * void SHA256_Final(unsigned char [32], SHA256_CTX *); +*/ +void libscrypt_SHA256_Final(/*@out@*/ unsigned char [], SHA256_CTX *); +void libscrypt_HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); +void libscrypt_HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); + +/* Original declaration: + * void HMAC_SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *); +*/ +void libscrypt_HMAC_SHA256_Final(unsigned char [], HMAC_SHA256_CTX *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void libscrypt_PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/libscrypt/slowequals.c b/libscrypt/slowequals.c new file mode 100644 index 000000000..48e488e4e --- /dev/null +++ b/libscrypt/slowequals.c @@ -0,0 +1,26 @@ +#include + +/* Implements a constant time version of strcmp() + * Will return 1 if a and b are equal, 0 if they are not */ +int slow_equals(const char* a, const char* b) +{ + size_t lena, lenb, diff, i; + lena = strlen(a); + lenb = strlen(b); + diff = strlen(a) ^ strlen(b); + + for(i=0; i we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include + +#else + +#include +#ifdef _MSC_VER + #define INLINE __inline +#else + #define INLINE inline +#endif + +static INLINE uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static INLINE void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static INLINE uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static INLINE void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static INLINE uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static INLINE void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static INLINE uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static INLINE void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ From a3cc9cc10bffb3dcbdd06a86d7636993b00c7ff6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 22:06:21 +0200 Subject: [PATCH 52/70] Ability to import version 1 keys. Possibly. --- alethzero/Main.ui | 8 ++- alethzero/MainWin.cpp | 27 +++++++++ alethzero/MainWin.h | 1 + libdevcrypto/SecretStore.cpp | 105 +++++++++++++++++++++++++++-------- libdevcrypto/SecretStore.h | 4 +- 5 files changed, 120 insertions(+), 25 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b5e22409d..f37f532a2 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -157,6 +157,7 @@ + @@ -1656,7 +1657,7 @@ font-size: 14pt &Enable Local Addresses - + true @@ -1745,6 +1746,11 @@ font-size: 14pt Co&nfirm Transactions + + + Import &Secret Key File... + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 07f48c0bc..4f1da1c1a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -813,6 +813,33 @@ void Main::on_importKey_triggered() } void Main::on_importKeyFile_triggered() +{ + QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); + h128 uuid = m_keyManager.store().importKey(s.toStdString()); + if (!uuid) + { + QMessageBox::warning(this, "Key File Invalid", "Could not find secret key definition. This is probably not an Web3 key file."); + return; + } + + QString info = QInputDialog::getText(this, "Import Key File", "Enter a description of this key to help you recognise it in the future."); + + QString pass; + for (Secret s; !s;) + { + s = Secret(m_keyManager.store().secret(uuid, [&](){ + pass = QInputDialog::getText(this, "Import Key File", "Enter the password for the key to complete the import.", QLineEdit::Password); + return pass.toStdString(); + }, false)); + if (!s && QMessageBox::question(this, "Import Key File", "The password you provided is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) + return; + } + + QString hint = QInputDialog::getText(this, "Import Key File", "Enter a hint for this password to help you remember it."); + m_keyManager.importExisting(uuid, info.toStdString(), pass.toStdString(), hint.toStdString()); +} + +void Main::on_claimPresale_triggered() { QString s = QFileDialog::getOpenFileName(this, "Claim Account Contents", QDir::homePath(), "JSON Files (*.json);;All Files (*)"); try diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 9f2082dd0..fdf7a9a72 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -138,6 +138,7 @@ private slots: void on_killAccount_triggered(); void on_importKey_triggered(); void on_importKeyFile_triggered(); + void on_claimPresale_triggered(); void on_exportKey_triggered(); // Account pane diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 7bc870bcf..e422c32f8 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -22,6 +22,7 @@ #include "SecretStore.h" #include #include +#include #include #include #include @@ -42,10 +43,10 @@ SecretStore::~SecretStore() { } -bytes SecretStore::secret(h128 const& _uuid, function const& _pass) const +bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { auto rit = m_cached.find(_uuid); - if (rit != m_cached.end()) + if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); if (it == m_keys.end()) @@ -101,28 +102,71 @@ void SecretStore::save(std::string const& _keysPath) } } +static js::mValue upgraded(std::string const& _s) +{ + js::mValue v; + js::read_string(_s, v); + if (v.type() != js::obj_type) + return js::mValue(); + js::mObject ret = v.get_obj(); + unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0; + if (version == 1) + { + // upgrade to version 2 + js::mObject old; + swap(old, ret); + + ret["id"] = old["Id"]; + js::mObject c; + c["ciphertext"] = old["Crypto"].get_obj()["CipherText"]; + c["cipher"] = "aes-128-cbc"; + { + js::mObject cp; + cp["iv"] = old["Crypto"].get_obj()["IV"]; + c["cipherparams"] = cp; + } + c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"]; + { + js::mObject kp; + kp["salt"] = old["Crypto"].get_obj()["Salt"]; + for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj()) + if (i.first != "SaltLen") + kp[boost::to_lower_copy(i.first)] = i.second; + c["kdfparams"] = kp; + } + c["sillymac"] = old["Crypto"].get_obj()["MAC"]; + c["sillymacjson"] = _s; + ret["crypto"] = c; + version = 2; + } + if (version == 2) + return ret; + return js::mValue(); +} + void SecretStore::load(std::string const& _keysPath) { fs::path p(_keysPath); boost::filesystem::create_directories(p); - js::mValue v; for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) if (is_regular_file(it->path())) - { - cdebug << "Reading" << it->path(); - js::read_string(contentsString(it->path().string()), v); - if (v.type() == js::obj_type) - { - js::mObject o = v.get_obj(); - int version = o.count("Version") ? stoi(o["Version"].get_str()) : o.count("version") ? o["version"].get_int() : 0; - if (version == 2) - m_keys[fromUUID(o["id"].get_str())] = make_pair(js::write_string(o["crypto"], false), it->path().string()); - else - cwarn << "Cannot read key version" << version; - } -// else -// cwarn << "Invalid JSON in key file" << it->path().string(); - } + readKey(it->path().string(), true); +} + +h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) +{ + cdebug << "Reading" << _file; + js::mValue u = upgraded(contentsString(_file)); + if (u.type() == js::obj_type) + { + js::mObject& o = u.get_obj(); + auto uuid = fromUUID(o["id"].get_str()); + m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _deleteFile ? _file : string()); + return uuid; + } + else + cwarn << "Invalid JSON in key file" << _file; + return h128(); } std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass) @@ -202,13 +246,28 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) bytes cipherText = fromHex(o["ciphertext"].get_str()); // check MAC - h256 mac(o["mac"].get_str()); - h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); - if (mac != macExp) + if (o.count("mac")) { - cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); - return bytes(); + h256 mac(o["mac"].get_str()); + h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + if (mac != macExp) + { + cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); + return bytes(); + } } + else if (o.count("sillymac")) + { + h256 mac(o["sillymac"].get_str()); + h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + if (mac != macExp) + { + cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); + return bytes(); + } + } + else + cwarn << "No MAC. Proceeding anyway."; // decrypt if (o["cipher"].get_str() == "aes-128-cbc") diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 18c290c1f..171603053 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -36,7 +36,8 @@ public: SecretStore(); ~SecretStore(); - bytes secret(h128 const& _uuid, std::function const& _pass) const; + bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } h128 importSecret(bytes const& _s, std::string const& _pass); void kill(h128 const& _uuid); @@ -48,6 +49,7 @@ private: void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); static std::string encrypt(bytes const& _v, std::string const& _pass); static bytes decrypt(std::string const& _v, std::string const& _pass); + h128 readKey(std::string const& _file, bool _deleteFile); mutable std::unordered_map m_cached; std::unordered_map> m_keys; From 29cbfdb25dfb2c464038a6ce0c48a60a5eec1167 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 23:01:51 +0200 Subject: [PATCH 53/70] allow reencrypting key. windows fix. --- alethzero/Main.ui | 6 +++++ alethzero/MainWin.cpp | 16 +++++++++++- alethzero/MainWin.h | 1 + libdevcrypto/SecretStore.cpp | 47 ++++++++++++++++++++++++++++-------- libdevcrypto/SecretStore.h | 8 +++++- libethereum/KeyManager.cpp | 33 ++++++++++++++++--------- libethereum/KeyManager.h | 3 +++ libscrypt/crypto-mcf.c | 2 +- 8 files changed, 91 insertions(+), 25 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index f37f532a2..b97ed08ed 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -159,6 +159,7 @@ + @@ -1751,6 +1752,11 @@ font-size: 14pt Import &Secret Key File... + + + &Re-encrypt Key + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4f1da1c1a..a2d7a3dde 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2016,7 +2016,7 @@ void Main::on_killAccount_triggered() { if (ui->ourAccounts->currentRow() >= 0) { - auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); + auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address h((byte const*)hba.data(), Address::ConstructFromPointer); auto k = m_keyManager.accountDetails()[h]; if ( @@ -2036,6 +2036,20 @@ void Main::on_killAccount_triggered() } } +void Main::on_reencryptKey_triggered() +{ + if (ui->ourAccounts->currentRow() >= 0) + { + auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); + Address a((byte const*)hba.data(), Address::ConstructFromPointer); + QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"}; + QString kdf = QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your key:", kdfs); + m_keyManager.reencode(a, [&](){ + return QInputDialog::getText(nullptr, "Re-Encrypt Key", "Enter the password for this key to re-encrypt it.", QLineEdit::Password, QString()).toStdString(); + }, (KDF)kdfs.indexOf(kdf)); + } +} + void Main::on_go_triggered() { if (!ui->net->isChecked()) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index fdf7a9a72..6628c649b 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -137,6 +137,7 @@ private slots: void on_newAccount_triggered(); void on_killAccount_triggered(); void on_importKey_triggered(); + void on_reencryptKey_triggered(); void on_importKeyFile_triggered(); void on_claimPresale_triggered(); void on_exportKey_triggered(); diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index e422c32f8..6a975525b 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -169,24 +169,51 @@ h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) return h128(); } -std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass) +void SecretStore::recode(h128 const& _uuid, string const& _pass, KDF _kdf) +{ + m_keys[_uuid].first = encrypt(secret(_uuid, [&](){ return _pass; }), _pass, _kdf); + save(); +} + +std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF _kdf) { js::mObject ret; // KDF info unsigned dklen = 16; - unsigned iterations = 262144; bytes salt = h256::random().asBytes(); - ret["kdf"] = "pbkdf2"; + bytes derivedKey; + if (_kdf == KDF::Scrypt) { - js::mObject params; - params["prf"] = "hmac-sha256"; - params["c"] = (int)iterations; - params["salt"] = toHex(salt); - params["dklen"] = (int)dklen; - ret["kdfparams"] = params; + unsigned iterations = 262144; + unsigned p = 262144; + unsigned r = 262144; + ret["kdf"] = "scrypt"; + { + js::mObject params; + params["n"] = (int)iterations; + params["p"] = 1; + params["r"] = 8; + params["dklen"] = (int)dklen; + params["salt"] = toHex(salt); + ret["kdfparams"] = params; + } + derivedKey = scrypt(_pass, salt, iterations, p, r, dklen); + } + else + { + unsigned iterations = 262144; + ret["kdf"] = "pbkdf2"; + { + js::mObject params; + params["prf"] = "hmac-sha256"; + params["c"] = (int)iterations; + params["salt"] = toHex(salt); + params["dklen"] = (int)dklen; + ret["kdfparams"] = params; + } + derivedKey = pbkdf2(_pass, salt, iterations, dklen); } - bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen); // cipher info ret["cipher"] = "aes-128-cbc"; diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 171603053..6e66ce967 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -30,6 +30,11 @@ namespace dev { +enum class KDF { + PBKDF2_SHA256, + Scrypt, +}; + class SecretStore { public: @@ -39,6 +44,7 @@ public: bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } h128 importSecret(bytes const& _s, std::string const& _pass); + void recode(h128 const& _uuid, std::string const& _pass, KDF _kdf = KDF::Scrypt); void kill(h128 const& _uuid); // Clear any cached keys. @@ -47,7 +53,7 @@ public: private: void save(std::string const& _keysPath = getDataDir("web3") + "/keys"); void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); - static std::string encrypt(bytes const& _v, std::string const& _pass); + static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); static bytes decrypt(std::string const& _v, std::string const& _pass); h128 readKey(std::string const& _file, bool _deleteFile); diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp index 8c3fd28c3..687e13991 100644 --- a/libethereum/KeyManager.cpp +++ b/libethereum/KeyManager.cpp @@ -49,6 +49,12 @@ void KeyManager::create(std::string const& _pass) write(_pass, m_keysFile); } +void KeyManager::reencode(Address const& _address, std::function const& _pass, KDF _kdf) +{ + h128 u = uuid(_address); + store().recode(u, getPassword(u, _pass), _kdf); +} + bool KeyManager::load(std::string const& _pass) { try { @@ -89,18 +95,21 @@ Secret KeyManager::secret(Address const& _address, function const Secret KeyManager::secret(h128 const& _uuid, function const& _pass) const { - return Secret(m_store.secret(_uuid, [&](){ - auto kit = m_keyInfo.find(_uuid); - if (kit != m_keyInfo.end()) - { - auto it = m_cachedPasswords.find(kit->second.passHash); - if (it != m_cachedPasswords.end()) - return it->second; - } - std::string p = _pass(); - m_cachedPasswords[hashPassword(p)] = p; - return p; - })); + return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); })); +} + +std::string KeyManager::getPassword(h128 const& _uuid, function const& _pass) const +{ + auto kit = m_keyInfo.find(_uuid); + if (kit != m_keyInfo.end()) + { + auto it = m_cachedPasswords.find(kit->second.passHash); + if (it != m_cachedPasswords.end()) + return it->second; + } + std::string p = _pass(); + m_cachedPasswords[hashPassword(p)] = p; + return p; } h128 KeyManager::uuid(Address const& _a) const diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index 0a83fcc00..2cacf7bfe 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -84,10 +84,13 @@ public: Secret secret(Address const& _address, std::function const& _pass = DontKnowThrow) const; Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; + void reencode(Address const& _address, std::function const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt); + void kill(h128 const& _id) { kill(address(_id)); } void kill(Address const& _a); private: + std::string getPassword(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; std::string defaultPassword() const { return asString(m_key.ref()); } h256 hashPassword(std::string const& _pass) const; diff --git a/libscrypt/crypto-mcf.c b/libscrypt/crypto-mcf.c index 8ad3eb826..9f7ddc376 100644 --- a/libscrypt/crypto-mcf.c +++ b/libscrypt/crypto-mcf.c @@ -7,7 +7,7 @@ #include #ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ -#include +//#include #endif #include "libscrypt.h" From 74a69ebb16804f86ea4efc523d20439028d521d7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 20 May 2015 23:23:23 +0200 Subject: [PATCH 54/70] Windows build fix? --- libscrypt/crypto-scrypt-saltgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscrypt/crypto-scrypt-saltgen.c b/libscrypt/crypto-scrypt-saltgen.c index a0e29988c..3c22f84f7 100644 --- a/libscrypt/crypto-scrypt-saltgen.c +++ b/libscrypt/crypto-scrypt-saltgen.c @@ -5,7 +5,7 @@ #include #ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ -#include +//#include #endif #define RNGDEV "/dev/urandom" From 82145e1bb46c5a098994e3b2232cf433865d1654 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 21 May 2015 11:03:36 +0200 Subject: [PATCH 55/70] avoid unixy salt gen on windows. --- libscrypt/crypto-scrypt-saltgen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libscrypt/crypto-scrypt-saltgen.c b/libscrypt/crypto-scrypt-saltgen.c index 3c22f84f7..998a1abcb 100644 --- a/libscrypt/crypto-scrypt-saltgen.c +++ b/libscrypt/crypto-scrypt-saltgen.c @@ -1,3 +1,4 @@ +#ifndef _MSC_VER #include #include #include @@ -46,3 +47,4 @@ int libscrypt_salt_gen(uint8_t *salt, size_t len) return 0; } +#endif From 2bf4c443a9077c5e6c53359bb1f10cbc0280b4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 21 May 2015 13:11:13 +0200 Subject: [PATCH 56/70] Apply recent VM interface changes to EVM JIT. --- evmjit/libevmjit-cpp/Env.cpp | 25 +++++++++++++++---------- evmjit/libevmjit-cpp/JitVM.h | 6 +++++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index d1f239f9f..86a65dbab 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -64,19 +64,24 @@ extern "C" EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, int64_t _callGas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { - auto value = llvm2eth(*_value); - auto receiveAddress = right160(*_receiveAddress); - auto codeAddress = right160(*_codeAddress); - const auto isCall = receiveAddress == codeAddress; // OPT: The same address pointer can be used if not CODECALL + CallParameters params; + params.value = llvm2eth(*_value); + params.senderAddress = _env->myAddress; + params.receiveAddress = right160(*_receiveAddress); + params.codeAddress = right160(*_codeAddress); + params.data = {_inBeg, _inSize}; + params.out = {_outBeg, _outSize}; + params.onOp = {}; + const auto isCall = params.receiveAddress == params.codeAddress; // OPT: The same address pointer can be used if not CODECALL *io_gas -= _callGas; if (*io_gas < 0) return false; - if (isCall && !_env->exists(receiveAddress)) + if (isCall && !_env->exists(params.receiveAddress)) *io_gas -= static_cast(c_callNewAccountGas); // no underflow, *io_gas non-negative before - if (value > 0) // value transfer + if (params.value > 0) // value transfer { /*static*/ assert(c_callValueTransferGas > c_callStipend && "Overflow possible"); *io_gas -= static_cast(c_callValueTransferGas); // no underflow @@ -87,11 +92,11 @@ extern "C" return false; auto ret = false; - auto callGas = u256{_callGas}; - if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) - ret = _env->call(receiveAddress, value, {_inBeg, _inSize}, callGas, {_outBeg, _outSize}, {}, {}, codeAddress); + params.gas = u256{_callGas}; + if (_env->balance(_env->myAddress) >= params.value && _env->depth < 1024) + ret = _env->call(params); - *io_gas += static_cast(callGas); // it is never more than initial _callGas + *io_gas += static_cast(params.gas); // it is never more than initial _callGas return ret; } diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 58caa3648..38ef9ff61 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -12,10 +12,14 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + virtual u256 gas() const noexcept { return m_gas; } + virtual void reset(u256 const& _gas = 0) noexcept { m_gas = _gas; } + private: friend class VMFactory; - explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} + explicit JitVM(u256 _gas = 0): m_gas(_gas) {} + u256 m_gas; jit::RuntimeData m_data; jit::ExecutionEngine m_engine; std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT From 4fefa1f266fcbc9d55e425929ddcd52a7bc1e5c4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 21 May 2015 17:16:27 +0200 Subject: [PATCH 57/70] bug fix --- mix/ClientModel.cpp | 10 +++++----- mix/CodeModel.cpp | 4 +++- mix/CodeModel.h | 2 +- mix/qml/QBoolTypeView.qml | 29 ++++++++++++++++++++++------- mix/qml/StateDialog.qml | 15 +++++++++++++-- mix/qml/StateListModel.qml | 1 + mix/qml/StructView.qml | 3 +++ mix/qml/TransactionDialog.qml | 3 +-- mix/qml/TransactionLog.qml | 22 ++++++++++++++++++++++ mix/qml/html/cm/inkpot.css | 7 ++++++- mix/qml/html/cm/solarized.css | 1 - 11 files changed, 77 insertions(+), 20 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 54d5db2b5..4b4eb70d1 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -389,7 +389,7 @@ std::pair ClientModel::resolvePair(QString const& _contractId) { std::pair ret; ret.first = _contractId; - ret.second = -1; + ret.second = 0; if (_contractId.startsWith("<") && _contractId.endsWith(">")) { QStringList values = ret.first.remove("<").remove(">").split(" - "); @@ -401,10 +401,10 @@ std::pair ClientModel::resolvePair(QString const& _contractId) QString ClientModel::resolveToken(std::pair const& _value, vector
const& _contracts) { - if (_value.second != -1) - return QString::fromStdString("0x" + dev::toHex(_contracts.at(_value.second).ref())); - else - return _value.first; + if (_contracts.size() > 0) + return QString::fromStdString("0x" + dev::toHex(_contracts.at(_value.second).ref())); + else + return _value.first; } std::pair ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index a73dc920e..81f01a556 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -197,6 +197,8 @@ CodeModel::~CodeModel() stop(); disconnect(this); releaseContracts(); + if (m_gasCostsMaps) + m_gasCostsMaps->deleteLater(); } void CodeModel::stop() @@ -358,7 +360,7 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) { if (m_gasCostsMaps) m_gasCostsMaps->deleteLater(); - m_gasCostsMaps = new GasMapWrapper(this); + m_gasCostsMaps = new GasMapWrapper(); for (std::string n: _cs.getContractNames()) { ContractDefinition const& contractDefinition = _cs.getContractDefinition(n); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 5291bdc72..75e350c58 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -137,7 +137,7 @@ class GasMapWrapper: public QObject Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT) public: - GasMapWrapper(QObject* _parent): QObject(_parent){} + GasMapWrapper(QObject* _parent = 0): QObject(_parent){} void push(QString _source, int _start, int _end, QString _value, bool _isInfinite); bool contains(QString _key); void insert(QString _source, QVariantList _variantList); diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml index c68b4e133..a95c12040 100644 --- a/mix/qml/QBoolTypeView.qml +++ b/mix/qml/QBoolTypeView.qml @@ -6,22 +6,37 @@ Item id: editRoot property string value property string defaultValue - property alias readOnly: !boolCombo.enabled + property bool readOnly: !boolCombo.enabled height: 20 width: 150 + onReadOnlyChanged: { + boolCombo.enabled = !readOnly; + } + + function init() + { + value = value === true ? "1" : value + value = value === false ? "0" : value; + value = value === "true" ? "1" : value + value = value === "false" ? "0" : value; + + if (value === "") + boolCombo.currentIndex = parseInt(defaultValue); + else + boolCombo.currentIndex = parseInt(value); + boolCombo.enabled = !readOnly; + } + Rectangle { anchors.fill: parent ComboBox { - property bool inited: false + property bool inited; Component.onCompleted: { - if (value === "") - currentIndex = parseInt(defaultValue); - else - currentIndex = parseInt(value); - inited = true + init(); + inited = true; } id: boolCombo diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index f8da6dabd..404a524f4 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -507,8 +507,13 @@ Dialog { Button { text: qsTr("OK") onClicked: { - close() - accepted() + if (titleField.text === "") + alertDialog.open() + else + { + close() + accepted() + } } } Button { @@ -517,6 +522,12 @@ Dialog { } } + MessageDialog + { + id: alertDialog + text: qsTr("Please provide a name.") + } + ListModel { id: accountsModel diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index a94188a23..d3062af9e 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -266,6 +266,7 @@ Item { var ctorTr = defaultTransactionItem(); ctorTr.functionId = c; ctorTr.contractId = c; + ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; ctorTr.sender = state.accounts[0].secret; state.transactions.push(ctorTr); changed = true; diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 4feab2166..cb38ba5ed 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -93,6 +93,9 @@ Column else item.value = getValue(); + if (ptype.category === QSolidityType.Bool) + item.init(); + item.onValueChanged.connect(function() { vals[pname] = item.value; valueChanged(); diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 1437c2562..e7fe22e51 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -94,7 +94,6 @@ Dialog { function loadCtorParameters(contractId) { paramsModel = []; - console.log(contractId); var contract = codeModel.contracts[contractId]; if (contract) { var params = contract.contract.constructor.parameters; @@ -154,7 +153,7 @@ Dialog { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { var contract = codeModel.contracts[contractFromToken(recipients.currentValue())]; if (contract) { - var func = contract.contract.functions[functionComboBox.currentIndex]; + var func = contract.contract.functions[functionComboBox.currentIndex - 1]; if (func) { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 16ed3e9bf..d31fe0786 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -73,8 +73,30 @@ Item { } } + CheckBox + { + text: qsTr("Mine") + onCheckedChanged: { + mineAction.enabled = !checked; + mineTimer.running = checked; + } + } + + Timer + { + id: mineTimer + repeat: true; + interval: 12000 + running: false + onTriggered: + { + clientModel.mine(); + } + } + Button { + id: mineBtn anchors.rightMargin: 9 anchors.verticalCenter: parent.verticalCenter action: mineAction diff --git a/mix/qml/html/cm/inkpot.css b/mix/qml/html/cm/inkpot.css index c6863e624..6a2d8d63a 100644 --- a/mix/qml/html/cm/inkpot.css +++ b/mix/qml/html/cm/inkpot.css @@ -52,7 +52,7 @@ span.CodeMirror-selectedtext { color: #ffffff !important; } .CodeMirror-errorannotation { border-bottom: 1px solid #DD3330; margin-bottom: 4px; -} + } .CodeMirror-errorannotation-context { font-family: monospace; @@ -63,3 +63,8 @@ span.CodeMirror-selectedtext { color: #ffffff !important; } border-top: solid 2px #063742; } +.CodeMirror-search-field +{ + font-size: 12px; +} + diff --git a/mix/qml/html/cm/solarized.css b/mix/qml/html/cm/solarized.css index 1d298b990..df0859d25 100644 --- a/mix/qml/html/cm/solarized.css +++ b/mix/qml/html/cm/solarized.css @@ -194,4 +194,3 @@ span.CodeMirror-selectedtext { color: #586e75 !important; } .CodeMirror-gasCosts { border-bottom: double 1px #2aa198; } - From f35a5ca84d4c369dcecb91bd34c1a859ad1a50d5 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 21 May 2015 20:43:35 +0200 Subject: [PATCH 58/70] fix mining in tests --- libethcore/Ethash.cpp | 2 +- libethcore/Miner.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 228f03f8e..24a6ab41e 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -142,7 +142,7 @@ void Ethash::CPUMiner::workLoop() WorkPackage w = work(); EthashAux::FullType dag; - while (!shouldStop() && !(dag = EthashAux::full(w.seedHash))) + while (!shouldStop() && !(dag = EthashAux::full(w.seedHash, true))) this_thread::sleep_for(chrono::milliseconds(500)); h256 boundary = w.boundary; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index cede34475..11b9ae140 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -44,7 +44,7 @@ struct MiningProgress // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return hashes * 1000 / ms; } + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } }; struct MineInfo: public MiningProgress {}; From 8399161a8e9b4f0cf3a38e14f5c83e566aad21c2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 21 May 2015 23:29:27 +0200 Subject: [PATCH 59/70] Nicer password dialog. Cleanups and fixes for secretstore and keyman. --- alethzero/CMakeLists.txt | 3 +- alethzero/GetPassword.ui | 123 ++++++++++++++++++++++++++++ alethzero/Main.ui | 8 +- alethzero/MainWin.cpp | 98 ++++++++++++++++++---- alethzero/MainWin.h | 3 +- alethzero/Transact.cpp | 27 +++++-- alethzero/Transact.h | 1 + libdevcore/Common.h | 3 + libdevcrypto/Common.cpp | 14 ++-- libdevcrypto/Common.h | 16 +++- libdevcrypto/SecretStore.cpp | 152 ++++++++++++++++++++++------------- libdevcrypto/SecretStore.h | 2 +- libethcore/ICAP.h | 2 - libethereum/AccountDiff.h | 2 +- libethereum/KeyManager.cpp | 14 +++- libethereum/KeyManager.h | 12 ++- 16 files changed, 380 insertions(+), 100 deletions(-) create mode 100644 alethzero/GetPassword.ui diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 41d9ea10f..595668cd1 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -23,6 +23,7 @@ qt5_wrap_ui(ui_Connect.h Connect.ui) qt5_wrap_ui(ui_Debugger.h Debugger.ui) qt5_wrap_ui(ui_Transact.h Transact.ui) qt5_wrap_ui(ui_ExportState.h ExportState.ui) +qt5_wrap_ui(ui_GetPassword.h GetPassword.ui) file(GLOB HEADERS "*.h") @@ -35,7 +36,7 @@ endif () # eth_add_executable is defined in cmake/EthExecutableHelper.cmake eth_add_executable(${EXECUTABLE} ICON alethzero - UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui + UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui WIN_RESOURCES alethzero.rc ) diff --git a/alethzero/GetPassword.ui b/alethzero/GetPassword.ui new file mode 100644 index 000000000..753bca565 --- /dev/null +++ b/alethzero/GetPassword.ui @@ -0,0 +1,123 @@ + + + GetPassword + + + + 0 + 0 + 400 + 187 + + + + Enter Password + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::RichText + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QLineEdit::Password + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + GetPassword + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + GetPassword + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b97ed08ed..ecdc07ab6 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -159,6 +159,7 @@ + @@ -1754,7 +1755,12 @@ font-size: 14pt - &Re-encrypt Key + &Re-Encrypt Key + + + + + Re-Encrypt All Keys... diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a2d7a3dde..1dcdcb67f 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -75,6 +75,7 @@ #include "WebPage.h" #include "ExportState.h" #include "ui_Main.h" +#include "ui_GetPassword.h" using namespace std; using namespace dev; using namespace dev::p2p; @@ -467,7 +468,9 @@ void Main::load(QString _s) void Main::on_newTransaction_triggered() { m_transact.setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB); - m_transact.exec(); + m_transact.setWindowFlags(Qt::Dialog); + m_transact.setWindowModality(Qt::WindowModal); + m_transact.show(); } void Main::on_loadJS_triggered() @@ -698,12 +701,17 @@ Secret Main::retrieveSecret(Address const& _a) const auto info = m_keyManager.accountDetails()[_a]; while (true) { - if (Secret s = m_keyManager.secret(_a, [&](){ - return QInputDialog::getText(const_cast(this), "Import Account Key", QString("Enter the password for the account %2 (%1). The hint is:\n%3").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first)).arg(QString::fromStdString(info.second)), QLineEdit::Password).toStdString(); - })) + Secret s = m_keyManager.secret(_a, [&](){ + QDialog d; + Ui_GetPassword gp; + gp.setupUi(&d); + d.setWindowTitle("Unlock Account"); + gp.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first))); + gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(info.second)); + return d.exec() == QDialog::Accepted ? gp.entry->text().toStdString() : string(); + }); + if (s || QMessageBox::warning(nullptr, "Unlock Account", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) return s; - else if (QMessageBox::warning(const_cast(this), "Incorrect Password", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) - return Secret(); } } @@ -771,17 +779,32 @@ void Main::readSettings(bool _skipGeometry) on_urlEdit_returnPressed(); } -std::string Main::getPassword(std::string const& _title, std::string const& _for) +std::string Main::getPassword(std::string const& _title, std::string const& _for, std::string* _hint, bool* _ok) { QString password; while (true) { - password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString()); + bool ok; + password = QInputDialog::getText(nullptr, QString::fromStdString(_title), QString::fromStdString(_for), QLineEdit::Password, QString(), &ok); + if (!ok) + { + if (_ok) + *_ok = false; + return string(); + } + if (password.isEmpty()) + break; QString confirm = QInputDialog::getText(nullptr, QString::fromStdString(_title), "Confirm this password by typing it again", QLineEdit::Password, QString()); if (password == confirm) break; QMessageBox::warning(nullptr, QString::fromStdString(_title), "You entered two different passwords - please enter the same password twice.", QMessageBox::Ok); } + + if (!password.isEmpty() && _hint && !m_keyManager.haveHint(password.toStdString())) + *_hint = QInputDialog::getText(this, "Create Account", "Enter a hint to help you remember this password.").toStdString(); + + if (_ok) + *_ok = true; return password.toStdString(); } @@ -797,8 +820,11 @@ void Main::on_importKey_triggered() QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); if (QMessageBox::question(this, "Additional Security?", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - std::string password = getPassword("Import Account Key", "Enter the password you would like to use for this key. Don't forget it!"); - std::string hint = QInputDialog::getText(this, "Import Account Key", "Enter a hint to help you remember this password.").toStdString(); + bool ok; + std::string hint; + std::string password = getPassword("Import Account Key", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok); + if (!ok) + return; m_keyManager.import(k.secret(), s.toStdString(), password, hint); } else @@ -2003,8 +2029,11 @@ void Main::on_newAccount_triggered() QString s = QInputDialog::getText(this, "Create Account", "Enter this account's name"); if (QMessageBox::question(this, "Create Account", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!"); - std::string hint = QInputDialog::getText(this, "Create Account", "Enter a hint to help you remember this password.").toStdString(); + bool ok = false; + std::string hint; + std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!", &hint, &ok); + if (!ok) + return; m_keyManager.import(p.secret(), s.toStdString(), password, hint); } else @@ -2043,11 +2072,48 @@ void Main::on_reencryptKey_triggered() auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address a((byte const*)hba.data(), Address::ConstructFromPointer); QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"}; - QString kdf = QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your key:", kdfs); - m_keyManager.reencode(a, [&](){ - return QInputDialog::getText(nullptr, "Re-Encrypt Key", "Enter the password for this key to re-encrypt it.", QLineEdit::Password, QString()).toStdString(); - }, (KDF)kdfs.indexOf(kdf)); + bool ok = true; + KDF kdf = (KDF)kdfs.indexOf(QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your key:", kdfs, kdfs.size() - 1, false, &ok)); + if (!ok) + return; + std::string hint; + std::string password = getPassword("Create Account", "Enter the password you would like to use for this key. Don't forget it!\nEnter nothing to use your Master password.", &hint, &ok); + if (!ok) + return; + try { + auto pw = [&](){ + auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString(); + if (p.empty()) + throw UnknownPassword(); + return p; + }; + while (!(password.empty() ? m_keyManager.recode(a, SemanticPassword::Master, pw, kdf) : m_keyManager.recode(a, password, hint, pw, kdf))) + if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) + return; + } + catch (UnknownPassword&) {} + } +} + +void Main::on_reencryptAll_triggered() +{ + QStringList kdfs = {"PBKDF2-SHA256", "Scrypt"}; + bool ok = false; + QString kdf = QInputDialog::getItem(this, "Re-Encrypt Key", "Select a key derivation function to use for storing your keys:", kdfs, kdfs.size() - 1, false, &ok); + if (!ok) + return; + try { + for (Address const& a: m_keyManager.accounts()) + while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){ + auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString(); + if (p.empty()) + throw UnknownPassword(); + return p; + }, (KDF)kdfs.indexOf(kdf))) + if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) + return; } + catch (UnknownPassword&) {} } void Main::on_go_triggered() diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 6628c649b..0e74d8f69 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -138,6 +138,7 @@ private slots: void on_killAccount_triggered(); void on_importKey_triggered(); void on_reencryptKey_triggered(); + void on_reencryptAll_triggered(); void on_importKeyFile_triggered(); void on_claimPresale_triggered(); void on_exportKey_triggered(); @@ -248,7 +249,7 @@ private: void refreshBalances(); void setBeneficiary(dev::Address const& _b); - std::string getPassword(std::string const& _title, std::string const& _for); + std::string getPassword(std::string const& _title, std::string const& _for, std::string* _hint = nullptr, bool* _ok = nullptr); std::unique_ptr ui; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 1336c3f05..fcca822fe 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -76,6 +76,7 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e m_ethereum = _eth; m_natSpecDB = _natSpecDB; + auto old = ui->from->currentIndex(); ui->from->clear(); for (auto const& i: m_accounts) { @@ -84,6 +85,10 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(i))).arg(QString::fromStdString(d.first)); ui->from->addItem(s); } + if (old > -1 && old < ui->from->count()) + ui->from->setCurrentIndex(old); + else if (ui->from->count()) + ui->from->setCurrentIndex(0); } bool Transact::isCreation() const @@ -301,6 +306,9 @@ void Transact::rejigData() // Determine how much balance we have to play with... //findSecret(value() + ethereum()->gasLimitRemaining() * gasPrice()); auto s = fromAccount(); + if (!s) + return; + auto b = ethereum()->balanceAt(s, PendingBlock); m_allGood = true; @@ -344,7 +352,7 @@ void Transact::rejigData() if (b < value() + baseGas * gasPrice()) { // Not enough - bail. - bail("
ERROR No single account contains enough for paying even the basic amount of gas required.
"); + bail("
ERROR Account doesn't contain enough for paying even the basic amount of gas required.
"); return; } else @@ -417,6 +425,8 @@ Secret Transact::findSecret(u256 _totalReq) const Address Transact::fromAccount() { + if (ui->from->currentIndex() < 0 || ui->from->currentIndex() >= (int)m_accounts.size()) + return Address(); auto it = m_accounts.begin(); std::advance(it, ui->from->currentIndex()); return *it; @@ -425,14 +435,19 @@ Address Transact::fromAccount() void Transact::on_send_clicked() { // Secret s = findSecret(value() + fee()); - Secret s = m_context->retrieveSecret(fromAccount()); - auto b = ethereum()->balanceAt(KeyPair(s).address(), PendingBlock); - if (!s || b < value() + fee()) + auto a = fromAccount(); + auto b = ethereum()->balanceAt(a, PendingBlock); + + if (!a || b < value() + fee()) { - QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); + QMessageBox::critical(nullptr, "Transaction Failed", "Couldn't make transaction: account doesn't contain at least the required amount.", QMessageBox::Ok); return; } + Secret s = m_context->retrieveSecret(a); + if (!s) + return; + if (isCreation()) { // If execution is a contract creation, add Natspec to @@ -467,7 +482,7 @@ void Transact::on_debug_clicked() auto b = ethereum()->balanceAt(from, PendingBlock); if (!from || b < value() + fee()) { - QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); + QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: account doesn't contain at least the required amount."); return; } diff --git a/alethzero/Transact.h b/alethzero/Transact.h index cd62c0e20..8c079a2fe 100644 --- a/alethzero/Transact.h +++ b/alethzero/Transact.h @@ -44,6 +44,7 @@ public: void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); private slots: + void on_from_currentIndexChanged(int) { rejigData(); } void on_destination_currentTextChanged(QString); void on_value_valueChanged(int) { updateFee(); } void on_gas_valueChanged(int) { updateFee(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index ac4d89103..ae98861c1 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #pragma warning(push) @@ -63,6 +64,8 @@ namespace dev extern char const* Version; +static const std::string EmptyString; + // Binary data types. using bytes = std::vector; using bytesRef = vector_ref; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 2a3561314..814f8309e 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -120,10 +120,11 @@ std::pair dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plai return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); } -bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) +bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain) { - const int c_aesKeyLen = 16; - SecByteBlock key(_k.data(), c_aesKeyLen); + if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) + return bytes(); + SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode::Encryption e; @@ -139,10 +140,11 @@ bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plai } } -bytes dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) +bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) { - const size_t c_aesKeyLen = 16; - SecByteBlock key(_k.data(), c_aesKeyLen); + if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) + return bytes(); + SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode::Decryption d; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index a0f894a25..10bcdd067 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -98,18 +98,26 @@ bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); /// Encrypt payload using ECIES standard with AES128-CTR. void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); - + /// Decrypt payload using ECIES standard with AES128-CTR. bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); - + /// Encrypts payload with random IV/ctr using AES128-CTR. std::pair encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); /// Encrypts payload with specified IV/ctr using AES128-CTR. -bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain); +bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); + +/// Decrypts payload with specified IV/ctr using AES128-CTR. +bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); + +/// Encrypts payload with specified IV/ctr using AES128-CTR. +inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } /// Decrypts payload with specified IV/ctr using AES128-CTR. -bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher); +inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 6a975525b..982b7bae6 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -34,6 +34,56 @@ using namespace dev; namespace js = json_spirit; namespace fs = boost::filesystem; +static const int c_keyFileVersion = 3; + +static js::mValue upgraded(std::string const& _s) +{ + js::mValue v; + js::read_string(_s, v); + if (v.type() != js::obj_type) + return js::mValue(); + js::mObject ret = v.get_obj(); + unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0; + if (version == 1) + { + // upgrade to version 2 + js::mObject old; + swap(old, ret); + + ret["id"] = old["Id"]; + js::mObject c; + c["ciphertext"] = old["Crypto"].get_obj()["CipherText"]; + c["cipher"] = "aes-128-cbc"; + { + js::mObject cp; + cp["iv"] = old["Crypto"].get_obj()["IV"]; + c["cipherparams"] = cp; + } + c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"]; + { + js::mObject kp; + kp["salt"] = old["Crypto"].get_obj()["Salt"]; + for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj()) + if (i.first != "SaltLen") + kp[boost::to_lower_copy(i.first)] = i.second; + c["kdfparams"] = kp; + } + c["sillymac"] = old["Crypto"].get_obj()["MAC"]; + c["sillymacjson"] = _s; + ret["crypto"] = c; + version = 2; + } + if (version == 2) + { + ret["crypto"].get_obj()["cipher"] = "aes-128-ctr"; + ret["crypto"].get_obj()["compat"] = "2"; + version = 3; + } + if (version == c_keyFileVersion) + return ret; + return js::mValue(); +} + SecretStore::SecretStore() { load(); @@ -45,6 +95,7 @@ SecretStore::~SecretStore() bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { + (void)_pass; auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; @@ -94,7 +145,7 @@ void SecretStore::save(std::string const& _keysPath) js::read_string(k.second.first, crypto); v["crypto"] = crypto; v["id"] = uuid; - v["version"] = 2; + v["version"] = c_keyFileVersion; writeFile(filename, js::write_string(js::mValue(v), true)); if (!k.second.second.empty() && k.second.second != filename) boost::filesystem::remove(k.second.second); @@ -102,48 +153,6 @@ void SecretStore::save(std::string const& _keysPath) } } -static js::mValue upgraded(std::string const& _s) -{ - js::mValue v; - js::read_string(_s, v); - if (v.type() != js::obj_type) - return js::mValue(); - js::mObject ret = v.get_obj(); - unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0; - if (version == 1) - { - // upgrade to version 2 - js::mObject old; - swap(old, ret); - - ret["id"] = old["Id"]; - js::mObject c; - c["ciphertext"] = old["Crypto"].get_obj()["CipherText"]; - c["cipher"] = "aes-128-cbc"; - { - js::mObject cp; - cp["iv"] = old["Crypto"].get_obj()["IV"]; - c["cipherparams"] = cp; - } - c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"]; - { - js::mObject kp; - kp["salt"] = old["Crypto"].get_obj()["Salt"]; - for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj()) - if (i.first != "SaltLen") - kp[boost::to_lower_copy(i.first)] = i.second; - c["kdfparams"] = kp; - } - c["sillymac"] = old["Crypto"].get_obj()["MAC"]; - c["sillymacjson"] = _s; - ret["crypto"] = c; - version = 2; - } - if (version == 2) - return ret; - return js::mValue(); -} - void SecretStore::load(std::string const& _keysPath) { fs::path p(_keysPath); @@ -169,10 +178,17 @@ h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) return h128(); } -void SecretStore::recode(h128 const& _uuid, string const& _pass, KDF _kdf) +bool SecretStore::recode(h128 const& _uuid, string const& _newPass, std::function const& _pass, KDF _kdf) { - m_keys[_uuid].first = encrypt(secret(_uuid, [&](){ return _pass; }), _pass, _kdf); + cdebug << "recode:" << toUUID(_uuid); + cdebug << "newPass:" << _newPass; + bytes s = secret(_uuid, _pass, true); + if (s.empty()) + return false; + cdebug << "secret:" << toHex(s); + m_keys[_uuid].first = encrypt(s, _newPass, _kdf); save(); + return true; } std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF _kdf) @@ -180,25 +196,26 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF js::mObject ret; // KDF info - unsigned dklen = 16; + unsigned dklen = 32; bytes salt = h256::random().asBytes(); bytes derivedKey; if (_kdf == KDF::Scrypt) { unsigned iterations = 262144; - unsigned p = 262144; - unsigned r = 262144; + unsigned p = 1; + unsigned r = 8; ret["kdf"] = "scrypt"; { js::mObject params; - params["n"] = (int)iterations; - params["p"] = 1; - params["r"] = 8; + params["n"] = (int64_t)iterations; + params["p"] = (int)p; + params["r"] = (int)r; params["dklen"] = (int)dklen; params["salt"] = toHex(salt); ret["kdfparams"] = params; } derivedKey = scrypt(_pass, salt, iterations, p, r, dklen); + cdebug << "derivedKey" << toHex(derivedKey); } else { @@ -213,11 +230,13 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF ret["kdfparams"] = params; } derivedKey = pbkdf2(_pass, salt, iterations, dklen); + cdebug << "derivedKey" << toHex(derivedKey); } // cipher info - ret["cipher"] = "aes-128-cbc"; - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + ret["cipher"] = "aes-128-ctr"; + h128 key(derivedKey, h128::AlignLeft); + cdebug << "cipherKey" << key.hex(); h128 iv = h128::random(); { js::mObject params; @@ -230,7 +249,9 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF ret["ciphertext"] = toHex(cipherText); // and mac. - h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); + cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); + cdebug << "mac" << mac.hex(); ret["mac"] = toHex(mac.ref()); return js::write_string((js::mValue)ret, true); @@ -270,13 +291,23 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) return bytes(); } + if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2")) + { + cwarn << "Derived key's length too short (<32 bytes)"; + return bytes(); + } + bytes cipherText = fromHex(o["ciphertext"].get_str()); // check MAC if (o.count("mac")) { h256 mac(o["mac"].get_str()); - h256 macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + h256 macExp; + if (o.count("compat") && o["compat"].get_str() == "2") + macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + else + macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText); if (mac != macExp) { cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); @@ -297,12 +328,17 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) cwarn << "No MAC. Proceeding anyway."; // decrypt - if (o["cipher"].get_str() == "aes-128-cbc") + if (o["cipher"].get_str() == "aes-128-ctr") { auto params = o["cipherparams"].get_obj(); - h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); h128 iv(params["iv"].get_str()); - return decryptSymNoAuth(key, iv, &cipherText); + if (o.count("compat") && o["compat"].get_str() == "2") + { + h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + return decryptSymNoAuth(key, iv, &cipherText); + } + else + return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText); } else { diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 6e66ce967..6a62147b8 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -44,7 +44,7 @@ public: bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } h128 importSecret(bytes const& _s, std::string const& _pass); - void recode(h128 const& _uuid, std::string const& _pass, KDF _kdf = KDF::Scrypt); + bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); void kill(h128 const& _uuid); // Clear any cached keys. diff --git a/libethcore/ICAP.h b/libethcore/ICAP.h index b4229e1f5..a2456bd40 100644 --- a/libethcore/ICAP.h +++ b/libethcore/ICAP.h @@ -38,8 +38,6 @@ namespace eth struct InvalidICAP: virtual public dev::Exception {}; -static const std::string EmptyString; - /** * @brief Encapsulation of an ICAP address. * Can be encoded, decoded, looked-up and inspected. diff --git a/libethereum/AccountDiff.h b/libethereum/AccountDiff.h index 22107b958..dd494c0a5 100644 --- a/libethereum/AccountDiff.h +++ b/libethereum/AccountDiff.h @@ -62,7 +62,7 @@ struct AccountDiff Diff exist; ///< The account's existance; was it created/deleted or not? Diff balance; ///< The account's balance; did it alter? Diff nonce; ///< The account's nonce; did it alter? - std::unordered_map> storage; ///< The account's storage addresses; each has its own Diff. + std::map> storage; ///< The account's storage addresses; each has its own Diff. Diff code; ///< The account's code; in general this should only have changed if exist also changed. }; diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp index 687e13991..4a03d8435 100644 --- a/libethereum/KeyManager.cpp +++ b/libethereum/KeyManager.cpp @@ -49,10 +49,20 @@ void KeyManager::create(std::string const& _pass) write(_pass, m_keysFile); } -void KeyManager::reencode(Address const& _address, std::function const& _pass, KDF _kdf) +bool KeyManager::recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function const& _pass, KDF _kdf) +{ + noteHint(_newPass, _hint); + return store().recode(uuid(_address), _newPass, _pass, _kdf); +} + +bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass, KDF _kdf) { h128 u = uuid(_address); - store().recode(u, getPassword(u, _pass), _kdf); + if (_newPass == SemanticPassword::Existing) + return store().recode(u, getPassword(u, _pass), _pass, _kdf); + else if (_newPass == SemanticPassword::Master) + return store().recode(u, defaultPassword(), _pass, _kdf); + return false; } bool KeyManager::load(std::string const& _pass) diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index 2cacf7bfe..2fc47e9b5 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -42,6 +42,12 @@ struct KeyInfo static const auto DontKnowThrow = [](){ throw UnknownPassword(); return std::string(); }; +enum class SemanticPassword +{ + Existing, + Master +}; + // TODO: This one is specifically for Ethereum, but we can make it generic in due course. // TODO: hidden-partition style key-store. /** @@ -67,9 +73,12 @@ public: void save(std::string const& _pass) const { write(_pass, m_keysFile); } void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; } + void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordInfo[hashPassword(_pass)] = _hint; } + bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); } AddressHash accounts() const; std::unordered_map> accountDetails() const; + std::string const& hint(Address const& _a) const { try { return m_passwordInfo.at(m_keyInfo.at(m_addrLookup.at(_a)).passHash); } catch (...) { return EmptyString; } } h128 uuid(Address const& _a) const; Address address(h128 const& _uuid) const; @@ -84,7 +93,8 @@ public: Secret secret(Address const& _address, std::function const& _pass = DontKnowThrow) const; Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; - void reencode(Address const& _address, std::function const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt); + bool recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt); + bool recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt); void kill(h128 const& _id) { kill(address(_id)); } void kill(Address const& _a); From 422be5eb46052224efdacae652ccd0483b305323 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 22 May 2015 00:22:10 +0200 Subject: [PATCH 60/70] Fixes and use actual master password for encrypting by default. --- alethzero/Transact.h | 12 ++++----- libdevcrypto/SecretStore.cpp | 13 ++++----- libethereum/KeyManager.cpp | 52 +++++++++++++++++++++++++++--------- libethereum/KeyManager.h | 5 +++- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/alethzero/Transact.h b/alethzero/Transact.h index 8c079a2fe..c14fcc7e1 100644 --- a/alethzero/Transact.h +++ b/alethzero/Transact.h @@ -44,13 +44,13 @@ public: void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); private slots: - void on_from_currentIndexChanged(int) { rejigData(); } + void on_from_currentIndexChanged(int) { rejigData(); rejigData(); } void on_destination_currentTextChanged(QString); - void on_value_valueChanged(int) { updateFee(); } - void on_gas_valueChanged(int) { updateFee(); } - void on_valueUnits_currentIndexChanged(int) { updateFee(); } - void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); } - void on_gasPrice_valueChanged(int) { updateFee(); } + void on_value_valueChanged(int) { updateFee(); rejigData(); } + void on_gas_valueChanged(int) { updateFee(); rejigData(); } + void on_valueUnits_currentIndexChanged(int) { updateFee(); rejigData(); } + void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); rejigData(); } + void on_gasPrice_valueChanged(int) { updateFee(); rejigData(); } void on_data_textChanged() { rejigData(); } void on_optimize_clicked() { rejigData(); } void on_send_clicked(); diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 982b7bae6..68e18b5ab 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -180,12 +180,10 @@ h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) bool SecretStore::recode(h128 const& _uuid, string const& _newPass, std::function const& _pass, KDF _kdf) { - cdebug << "recode:" << toUUID(_uuid); - cdebug << "newPass:" << _newPass; +// cdebug << "recode:" << toUUID(_uuid); bytes s = secret(_uuid, _pass, true); if (s.empty()) return false; - cdebug << "secret:" << toHex(s); m_keys[_uuid].first = encrypt(s, _newPass, _kdf); save(); return true; @@ -215,7 +213,6 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF ret["kdfparams"] = params; } derivedKey = scrypt(_pass, salt, iterations, p, r, dklen); - cdebug << "derivedKey" << toHex(derivedKey); } else { @@ -230,13 +227,13 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF ret["kdfparams"] = params; } derivedKey = pbkdf2(_pass, salt, iterations, dklen); - cdebug << "derivedKey" << toHex(derivedKey); } +// cdebug << "derivedKey" << toHex(derivedKey); // cipher info ret["cipher"] = "aes-128-ctr"; h128 key(derivedKey, h128::AlignLeft); - cdebug << "cipherKey" << key.hex(); +// cdebug << "cipherKey" << key.hex(); h128 iv = h128::random(); { js::mObject params; @@ -250,8 +247,8 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF // and mac. h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); - cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); - cdebug << "mac" << mac.hex(); +// cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); +// cdebug << "mac" << mac.hex(); ret["mac"] = toHex(mac.ref()); return js::write_string((js::mValue)ret, true); diff --git a/libethereum/KeyManager.cpp b/libethereum/KeyManager.cpp index 4a03d8435..1edfe9cff 100644 --- a/libethereum/KeyManager.cpp +++ b/libethereum/KeyManager.cpp @@ -52,17 +52,27 @@ void KeyManager::create(std::string const& _pass) bool KeyManager::recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function const& _pass, KDF _kdf) { noteHint(_newPass, _hint); - return store().recode(uuid(_address), _newPass, _pass, _kdf); + h128 u = uuid(_address); + if (!store().recode(u, _newPass, [&](){ return getPassword(u, _pass); }, _kdf)) + return false; + + m_keyInfo[u].passHash = hashPassword(_newPass); + write(); + return true; } bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass, KDF _kdf) { h128 u = uuid(_address); + std::string p; if (_newPass == SemanticPassword::Existing) - return store().recode(u, getPassword(u, _pass), _pass, _kdf); + p = getPassword(u, _pass); else if (_newPass == SemanticPassword::Master) - return store().recode(u, defaultPassword(), _pass, _kdf); - return false; + p = defaultPassword(); + else + return false; + + return recode(_address, p, string(), _pass, _kdf); } bool KeyManager::load(std::string const& _pass) @@ -87,7 +97,8 @@ bool KeyManager::load(std::string const& _pass) m_password = (string)s[3]; } m_cachedPasswords[hashPassword(m_password)] = m_password; - m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword(); + m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref()); + m_cachedPasswords[m_master = hashPassword(_pass)] = _pass; return true; } catch (...) { @@ -111,15 +122,29 @@ Secret KeyManager::secret(h128 const& _uuid, function const& _pas std::string KeyManager::getPassword(h128 const& _uuid, function const& _pass) const { auto kit = m_keyInfo.find(_uuid); + h256 ph; if (kit != m_keyInfo.end()) + ph = kit->second.passHash; + return getPassword(ph, _pass); +} + +std::string KeyManager::getPassword(h256 const& _passHash, function const& _pass) const +{ + auto it = m_cachedPasswords.find(_passHash); + if (it != m_cachedPasswords.end()) + return it->second; + for (unsigned i = 0; i< 10; ++i) { - auto it = m_cachedPasswords.find(kit->second.passHash); - if (it != m_cachedPasswords.end()) - return it->second; + std::string p = _pass(); + if (p.empty()) + break; + if (hashPassword(p) == _passHash || !_passHash) + { + m_cachedPasswords[hashPassword(p)] = p; + return p; + } } - std::string p = _pass(); - m_cachedPasswords[hashPassword(p)] = p; - return p; + return string(); } h128 KeyManager::uuid(Address const& _a) const @@ -190,7 +215,7 @@ std::unordered_map> KeyManager::acc std::unordered_map> ret; for (auto const& i: m_addrLookup) if (m_keyInfo.count(i.second) > 0) - ret[i.first] = make_pair(m_keyInfo.at(i.second).info, m_passwordInfo.at(m_keyInfo.at(i.second).passHash)); + ret[i.first] = make_pair(m_keyInfo.count(i.second) ? m_keyInfo.at(i.second).info : "", m_keyInfo.count(i.second) && m_passwordInfo.count(m_keyInfo.at(i.second).passHash) ? m_passwordInfo.at(m_keyInfo.at(i.second).passHash) : ""); return ret; } @@ -213,6 +238,9 @@ void KeyManager::write(std::string const& _pass, std::string const& _keysFile) c bytes salt = h256::random().asBytes(); writeFile(_keysFile + ".salt", salt); auto key = h128(pbkdf2(_pass, salt, 262144, 16)); + + m_cachedPasswords[hashPassword(_pass)] = _pass; + m_master = hashPassword(_pass); write(key, _keysFile); } diff --git a/libethereum/KeyManager.h b/libethereum/KeyManager.h index 2fc47e9b5..3fcf83c3e 100644 --- a/libethereum/KeyManager.h +++ b/libethereum/KeyManager.h @@ -101,11 +101,13 @@ public: private: std::string getPassword(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; - std::string defaultPassword() const { return asString(m_key.ref()); } + std::string getPassword(h256 const& _passHash, std::function const& _pass = DontKnowThrow) const; + std::string defaultPassword(std::function const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); } h256 hashPassword(std::string const& _pass) const; // Only use if previously loaded ok. // @returns false if wasn't previously loaded ok. + bool write() const { return write(m_keysFile); } bool write(std::string const& _keysFile) const; void write(std::string const& _pass, std::string const& _keysFile) const; void write(h128 const& _key, std::string const& _keysFile) const; @@ -127,6 +129,7 @@ private: SecretStore m_store; mutable h128 m_key; + mutable h256 m_master; mutable std::string m_keysFile; }; From 9ba9536f73dcbb9714a6c5c180c67eb2ccac5ca9 Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Thu, 21 May 2015 21:19:57 -0400 Subject: [PATCH 61/70] Switched r and p --- libdevcrypto/SecretStore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 68e18b5ab..602ccce8d 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -206,13 +206,13 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF { js::mObject params; params["n"] = (int64_t)iterations; - params["p"] = (int)p; params["r"] = (int)r; + params["p"] = (int)p; params["dklen"] = (int)dklen; params["salt"] = toHex(salt); ret["kdfparams"] = params; } - derivedKey = scrypt(_pass, salt, iterations, p, r, dklen); + derivedKey = scrypt(_pass, salt, iterations, r, p, dklen); } else { @@ -280,7 +280,7 @@ bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) else if (o["kdf"].get_str() == "scrypt") { auto p = o["kdfparams"].get_obj(); - derivedKey = scrypt(_pass, fromHex(p["salt"].get_str()), p["n"].get_int(), p["p"].get_int(), p["r"].get_int(), p["dklen"].get_int()); + derivedKey = scrypt(_pass, fromHex(p["salt"].get_str()), p["n"].get_int(), p["r"].get_int(), p["p"].get_int(), p["dklen"].get_int()); } else { From bcc7ba2aadf7108d788d5211e12f7f1abb7b6fde Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 22 May 2015 15:05:13 +0200 Subject: [PATCH 62/70] small changes --- mix/ClientModel.cpp | 7 ++----- mix/CodeModel.cpp | 2 +- mix/CodeModel.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 4b4eb70d1..6b5242084 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -387,14 +387,11 @@ void ClientModel::executeSequence(vector const& _sequence, std::pair ClientModel::resolvePair(QString const& _contractId) { - std::pair ret; - ret.first = _contractId; - ret.second = 0; + std::pair ret = std::make_pair(_contractId, 0); if (_contractId.startsWith("<") && _contractId.endsWith(">")) { QStringList values = ret.first.remove("<").remove(">").split(" - "); - ret.first = values[0]; - ret.second = values[1].toUInt(); + ret = std::make_pair(values[0], values[1].toUInt()); } return ret; } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 81f01a556..424732c2b 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -360,7 +360,7 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) { if (m_gasCostsMaps) m_gasCostsMaps->deleteLater(); - m_gasCostsMaps = new GasMapWrapper(); + m_gasCostsMaps = new GasMapWrapper; for (std::string n: _cs.getContractNames()) { ContractDefinition const& contractDefinition = _cs.getContractDefinition(n); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 75e350c58..dcf3d0c1e 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -137,7 +137,7 @@ class GasMapWrapper: public QObject Q_PROPERTY(GasCostsMaps gasMaps MEMBER m_gasMaps CONSTANT) public: - GasMapWrapper(QObject* _parent = 0): QObject(_parent){} + GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){} void push(QString _source, int _start, int _end, QString _value, bool _isInfinite); bool contains(QString _key); void insert(QString _source, QVariantList _variantList); From 32e16bfa70b21371c46b1ad0a1dfdca38f63fa33 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 22 May 2015 16:33:12 +0200 Subject: [PATCH 63/70] small changes --- mix/CodeModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 424732c2b..d0f70683d 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -198,7 +198,7 @@ CodeModel::~CodeModel() disconnect(this); releaseContracts(); if (m_gasCostsMaps) - m_gasCostsMaps->deleteLater(); + delete m_gasCostsMaps; } void CodeModel::stop() From fcb629acdabf017b537ff873512abafdb6b8ccb7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 22 May 2015 18:14:13 +0200 Subject: [PATCH 64/70] ethkey utility with bare key tools. --- CMakeLists.txt | 19 +- alethzero/MainWin.h | 2 +- alethzero/Transact.cpp | 3 +- eth/main.cpp | 3 +- ethkey/CMakeLists.txt | 33 ++ ethkey/KeyAux.h | 351 +++++++++++++++++++++ ethkey/main.cpp | 84 +++++ ethminer/MinerAux.h | 4 +- exp/main.cpp | 3 +- libdevcore/CommonData.h | 9 + libdevcrypto/SecretStore.cpp | 2 +- libdevcrypto/SecretStore.h | 14 +- {libethereum => libethcore}/KeyManager.cpp | 7 +- {libethereum => libethcore}/KeyManager.h | 8 +- libweb3jsonrpc/AccountHolder.cpp | 3 +- 15 files changed, 528 insertions(+), 17 deletions(-) create mode 100644 ethkey/CMakeLists.txt create mode 100644 ethkey/KeyAux.h create mode 100644 ethkey/main.cpp rename {libethereum => libethcore}/KeyManager.cpp (96%) rename {libethereum => libethcore}/KeyManager.h (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8239e20a4..e7461eb1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,6 +251,17 @@ elseif (BUNDLE STREQUAL "user") set(NCURSES ${DECENT_PLATFORM}) set(TOOLS ON) set(TESTS OFF) +elseif (BUNDLE STREQUAL "wallet") + set(SERPENT OFF) + set(SOLIDITY OFF) + set(USENPM OFF) + set(GUI OFF) + set(NCURSES OFF) + set(TOOLS OFF) + set(TESTS OFF) + set(ETHKEY ON) + set(MINER OFF) + set(ETHASHCL ON) elseif (BUNDLE STREQUAL "miner") set(SERPENT OFF) set(SOLIDITY OFF) @@ -259,6 +270,7 @@ elseif (BUNDLE STREQUAL "miner") set(NCURSES OFF) set(TOOLS OFF) set(TESTS OFF) + set(ETHKEY OFF) set(MINER ON) set(ETHASHCL ON) endif () @@ -296,6 +308,7 @@ message("-- JSONRPC JSON-RPC support ${JSONRPC} message("-- USENPM Javascript source building ${USENPM}") message("------------------------------------------------------------- components") message("-- MINER Build miner ${MINER}") +message("-- ETHKEY Build wallet tools ${ETHKEY}") message("-- TOOLS Build basic tools ${TOOLS}") message("-- SOLIDITY Build Solidity language components ${SOLIDITY}") message("-- SERPENT Build Serpent language components ${SERPENT}") @@ -387,10 +400,14 @@ if (GENERAL) add_subdirectory(libwebthree) endif () -if (MINER) +if (MINER OR TOOLS) add_subdirectory(ethminer) endif () +if (ETHKEY OR TOOLS) + add_subdirectory(ethkey) +endif () + if (TESTS) add_subdirectory(libtestutils) add_subdirectory(test) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 0e74d8f69..29cd0dbf3 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -33,9 +33,9 @@ #include #include #include +#include #include #include -#include #include #include #include "Context.h" diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index fcca822fe..b485091d9 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -39,7 +39,8 @@ #include #include #include -#include +#include + #if ETH_SERPENT #include #include diff --git a/eth/main.cpp b/eth/main.cpp index 33d049843..a57928e72 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -37,7 +37,8 @@ #include #include #include -#include +#include + #include #if ETH_JSCONSOLE || !ETH_TRUE #include diff --git a/ethkey/CMakeLists.txt b/ethkey/CMakeLists.txt new file mode 100644 index 000000000..5575acbd0 --- /dev/null +++ b/ethkey/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) +include_directories(${Boost_INCLUDE_DIRS}) +include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) + +if (JSCONSOLE) + include_directories(${V8_INCLUDE_DIRS}) +endif() + +set(EXECUTABLE ethkey) + +file(GLOB HEADERS "*.h") + +add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +add_dependencies(${EXECUTABLE} BuildInfo.h) + +target_link_libraries(${EXECUTABLE} devcrypto) +target_link_libraries(${EXECUTABLE} ethcore) + +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) +endif() + +if (APPLE) + install(TARGETS ${EXECUTABLE} DESTINATION bin) +else() + eth_install_executable(${EXECUTABLE}) +endif() diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h new file mode 100644 index 000000000..daac72588 --- /dev/null +++ b/ethkey/KeyAux.h @@ -0,0 +1,351 @@ +#pragma once + +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file KeyAux.cpp + * @author Gav Wood + * @date 2014 + * CLI module for key management. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "BuildInfo.h" +using namespace std; +using namespace dev; +using namespace dev::eth; +using namespace boost::algorithm; + +#undef RETURN + +class BadArgument: public Exception {}; + +string getAccountPassword(KeyManager& keyManager, Address const& a) +{ + return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): "); +} + +string createPassword(std::string const& _prompt) +{ + string ret; + while (true) + { + ret = getPassword(_prompt); + string confirm = getPassword("Please confirm the password by entering it again: "); + if (ret == confirm) + break; + cout << "Passwords were different. Try again." << endl; + } + return ret; +// cout << "Enter a hint to help you remember this password: " << flush; +// cin >> hint; +// return make_pair(ret, hint); +} + +pair createPassword(KeyManager& _keyManager, std::string const& _prompt) +{ + string pass; + while (true) + { + pass = getPassword(_prompt); + string confirm = getPassword("Please confirm the password by entering it again: "); + if (pass == confirm) + break; + cout << "Passwords were different. Try again." << endl; + } + string hint; + if (!_keyManager.haveHint(pass)) + { + cout << "Enter a hint to help you remember this password: " << flush; + cin >> hint; + } + return make_pair(pass, hint); +} + +class KeyCLI +{ +public: + enum class OperationMode + { + None, + ListBare, + NewBare, + ImportBare, + ExportBare, + RecodeBare, + FirstWallet, + CreateWallet, + List = FirstWallet, + New, + Import, + Export, + Recode, + Kill + }; + + KeyCLI(OperationMode _mode = OperationMode::None): m_mode(_mode) {} + + bool interpretOption(int& i, int argc, char** argv) + { + string arg = argv[i]; + if (arg == "-n" || arg == "--new") + m_mode = OperationMode::New; + else if (arg == "--wallet-path" && i + 1 < argc) + m_walletPath = argv[++i]; + else if (arg == "--secrets-path" && i + 1 < argc) + m_secretsPath = argv[++i]; + else if ((arg == "-m" || arg == "--master") && i + 1 < argc) + m_masterPassword = argv[++i]; + else if (arg == "--unlock" && i + 1 < argc) + m_unlocks.push_back(argv[++i]); + else if (arg == "--lock" && i + 1 < argc) + m_lock = argv[++i]; + else if (arg == "--kdf" && i + 1 < argc) + m_kdf = argv[++i]; + else if (arg == "--kdf-param" && i + 2 < argc) + { + auto n = argv[++i]; + auto v = argv[++i]; + m_kdfParams[n] = v; + } + else if (arg == "--new-bare") + m_mode = OperationMode::NewBare; + else if (arg == "--import-bare") + m_mode = OperationMode::ImportBare; + else if (arg == "--list-bare") + m_mode = OperationMode::ListBare; + else if (arg == "--export-bare") + m_mode = OperationMode::ExportBare; + else if (arg == "--recode-bare") + m_mode = OperationMode::RecodeBare; + else if (arg == "--create-wallet") + m_mode = OperationMode::CreateWallet; + else if (arg == "--list") + m_mode = OperationMode::List; + else if ((arg == "-n" || arg == "--new") && i + 1 < argc) + { + m_mode = OperationMode::New; + m_name = argv[++i]; + } + else if ((arg == "-i" || arg == "--import") && i + 2 < argc) + { + m_mode = OperationMode::Import; + m_inputs = strings(1, argv[++i]); + m_name = argv[++i]; + } + else if (arg == "--export") + m_mode = OperationMode::Export; + else if (arg == "--recode") + m_mode = OperationMode::Recode; + else if (arg == "--no-icap") + m_icap = false; + else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) + m_inputs.push_back(arg); + else + return false; + return true; + } + + KeyPair makeKey() const + { + KeyPair k(Secret::random()); + while (m_icap && k.address()[0]) + k = KeyPair(sha3(k.secret())); + return k; + } + + void execute() + { + if (m_mode == OperationMode::CreateWallet) + { + KeyManager wallet(m_walletPath, m_secretsPath); + if (m_masterPassword.empty()) + m_masterPassword = createPassword("Please enter a MASTER password to protect your key store (make it strong!): "); + if (m_masterPassword.empty()) + cerr << "Aborted (empty password not allowed)." << endl; + else + wallet.create(m_masterPassword); + } + else if (m_mode < OperationMode::FirstWallet) + { + SecretStore store(m_secretsPath); + switch (m_mode) + { + case OperationMode::ListBare: + for (h128 const& u: std::set() + store.keys()) + cout << toUUID(u) << endl; + break; + case OperationMode::NewBare: + { + if (m_lock.empty()) + m_lock = createPassword("Enter a password with which to secure this account: "); + auto k = makeKey(); + store.importSecret(k.secret().asBytes(), m_lock); + cout << "Created key " << k.address().abridged() << endl; + cout << "Address: " << k.address().hex() << endl; + cout << "ICAP: " << ICAP(k.address()).encoded() << endl; + break; + } + case OperationMode::ImportBare: + for (string const& i: m_inputs) + { + h128 u; + bytes b; + b = fromHex(i); + if (b.size() != 32) + { + std::string s = contentsString(i); + b = fromHex(s); + if (b.size() != 32) + u = store.importKey(i); + } + if (!u && b.size() == 32) + u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); + else + { + cerr << "Cannot import " << i << " not a file or secret." << endl; + continue; + } + cout << "Successfully imported " << i << " as " << toUUID(u); + } + break; + case OperationMode::ExportBare: break; + case OperationMode::RecodeBare: + for (auto const& i: m_inputs) + { + h128 u = fromUUID(i); + if (u) + if (store.recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf())) + cerr << "Re-encoded " << toUUID(u) << endl; + else + cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl; + else + cerr << "Couldn't re-encode " << toUUID(u) << "; not found." << endl; + } + default: break; + } + } + else + { + KeyManager wallet(m_walletPath, m_secretsPath); + if (wallet.exists()) + while (true) + { + if (wallet.load(m_masterPassword)) + break; + if (!m_masterPassword.empty()) + { + cout << "Password invalid. Try again." << endl; + m_masterPassword.clear(); + } + m_masterPassword = getPassword("Please enter your MASTER password: "); + } + else + { + cerr << "Couldn't open wallet. Does it exist?" << endl; + exit(-1); + } + } + } + + std::string lockPassword(std::string const& _accountName) + { + return m_lock.empty() ? createPassword("Enter a password with which to secure account " + _accountName + ": ") : m_lock; + } + + static void streamHelp(ostream& _out) + { + _out + << "Secret-store (\"bare\") operation modes:" << endl + << " --list-bare List all secret available in secret-store." << endl + << " --new-bare Generate and output a key without interacting with wallet and dump the JSON." << endl + << " --import-bare [ | , ... ] Import keys from given sources." << endl + << " --recode-bare [ | , ... ] Decrypt and re-encrypt given keys." << endl +// << " --export-bare [ , ... ] Export given keys." << endl + << "Secret-store configuration:" << endl + << " --secrets-path Specify Web3 secret-store path (default: " << SecretStore::defaultPath() << ")" << endl + << endl + << "Wallet operating modes:" << endl + << " -l,--list List all keys available in wallet." << endl + << " -n,--new Create a new key with given name and add it in the wallet." << endl + << " -i,--import [||] Import keys from given source and place in wallet." << endl + << " -e,--export [
| , ... ] Export given keys." << endl + << " -r,--recode [
|| , ... ] Decrypt and re-encrypt given keys." << endl + << "Wallet configuration:" << endl + << " --create-wallet Create an Ethereum master wallet." << endl + << " --wallet-path Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl + << " -m, --master Specify wallet (master) password." << endl + << endl + << "Encryption configuration:" << endl + << " --kdf Specify KDF to use when encrypting (default: sc rypt)" << endl + << " --kdf-param Specify a parameter for the KDF." << endl +// << " --cipher Specify cipher to use when encrypting (default: aes-128-ctr)" << endl +// << " --cipher-param Specify a parameter for the cipher." << endl + << " --lock Specify password for when encrypting a (the) key." << endl + << endl + << "Decryption configuration:" << endl + << " --unlock Specify password for a (the) key." << endl + << "Key generation configuration:" << endl + << " --no-icap Don't bother to make a direct-ICAP capable key." << endl + ; + } + + static bool isTrue(std::string const& _m) + { + return _m == "on" || _m == "yes" || _m == "true" || _m == "1"; + } + + static bool isFalse(std::string const& _m) + { + return _m == "off" || _m == "no" || _m == "false" || _m == "0"; + } + +private: + KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; } + + /// Operating mode. + OperationMode m_mode; + + /// Wallet stuff + string m_secretsPath = SecretStore::defaultPath(); + string m_walletPath = KeyManager::defaultPath(); + + /// Wallet password stuff + string m_masterPassword; + strings m_unlocks; + string m_lock; + bool m_icap = true; + + /// Creating + string m_name; + + /// Importing + strings m_inputs; + + string m_kdf = "scrypt"; + map m_kdfParams; +// string m_cipher; +// map m_cipherParams; +}; diff --git a/ethkey/main.cpp b/ethkey/main.cpp new file mode 100644 index 000000000..53781a38a --- /dev/null +++ b/ethkey/main.cpp @@ -0,0 +1,84 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file main.cpp + * @author Gav Wood + * @date 2014 + * Ethereum client. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "BuildInfo.h" +#include "KeyAux.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +void help() +{ + cout + << "Usage ethkey [OPTIONS]" << endl + << "Options:" << endl << endl; + KeyCLI::streamHelp(cout); + cout + << "General Options:" << endl + << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl + << " -V,--version Show the version and exit." << endl + << " -h,--help Show this help message and exit." << endl + ; + exit(0); +} + +void version() +{ + cout << "ethkey version " << dev::Version << endl; + cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; + exit(0); +} + +int main(int argc, char** argv) +{ + KeyCLI m(KeyCLI::OperationMode::ListBare); + g_logVerbosity = 0; + + for (int i = 1; i < argc; ++i) + { + string arg = argv[i]; + if (m.interpretOption(i, argc, argv)) {} + else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) + g_logVerbosity = atoi(argv[++i]); + else if (arg == "-h" || arg == "--help") + help(); + else if (arg == "-V" || arg == "--version") + version(); + else + { + cerr << "Invalid argument: " << arg << endl; + exit(-1); + } + } + + m.execute(); + + return 0; +} + diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ef0621b7f..47fd2e2ae 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -16,10 +16,10 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file main.cpp +/** @file MinerAux.cpp * @author Gav Wood * @date 2014 - * Ethereum client. + * CLI module for mining. */ #include diff --git a/exp/main.cpp b/exp/main.cpp index 5162d915b..f0574fa7c 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -49,7 +49,8 @@ #include #include #include -#include +#include + #include #include #include diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 702f1f808..e1d8d7bdb 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -323,4 +323,13 @@ std::vector keysOf(std::map const& _m) return ret; } +template +std::vector keysOf(std::unordered_map const& _m) +{ + std::vector ret; + for (auto const& i: _m) + ret.push_back(i.first); + return ret; +} + } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 602ccce8d..c6f9803fa 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -84,7 +84,7 @@ static js::mValue upgraded(std::string const& _s) return js::mValue(); } -SecretStore::SecretStore() +SecretStore::SecretStore(std::string const& _path): m_path(_path) { load(); } diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 6a62147b8..c4e5d5cf7 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -38,7 +38,7 @@ enum class KDF { class SecretStore { public: - SecretStore(); + SecretStore(std::string const& _path = defaultPath()); ~SecretStore(); bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; @@ -47,18 +47,26 @@ public: bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); void kill(h128 const& _uuid); + std::vector keys() const { return keysOf(m_keys); } + // Clear any cached keys. void clearCache() const; + static std::string defaultPath() { return getDataDir("web3") + "/keys"; } + private: - void save(std::string const& _keysPath = getDataDir("web3") + "/keys"); - void load(std::string const& _keysPath = getDataDir("web3") + "/keys"); + void save(std::string const& _keysPath); + void load(std::string const& _keysPath); + void save() { save(m_path); } + void load() { load(m_path); } static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); static bytes decrypt(std::string const& _v, std::string const& _pass); h128 readKey(std::string const& _file, bool _deleteFile); mutable std::unordered_map m_cached; std::unordered_map> m_keys; + + std::string m_path; }; } diff --git a/libethereum/KeyManager.cpp b/libethcore/KeyManager.cpp similarity index 96% rename from libethereum/KeyManager.cpp rename to libethcore/KeyManager.cpp index 1edfe9cff..182201301 100644 --- a/libethereum/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -31,8 +31,8 @@ using namespace dev; using namespace eth; namespace fs = boost::filesystem; -KeyManager::KeyManager(std::string const& _keysFile): - m_keysFile(_keysFile) +KeyManager::KeyManager(std::string const& _keysFile, std::string const& _secretsPath): + m_keysFile(_keysFile), m_store(_secretsPath) {} KeyManager::~KeyManager() @@ -96,8 +96,11 @@ bool KeyManager::load(std::string const& _pass) m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; } + cdebug << hashPassword(m_password) << toHex(m_password); m_cachedPasswords[hashPassword(m_password)] = m_password; + cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref()); + cdebug << hashPassword(_pass) << _pass; m_cachedPasswords[m_master = hashPassword(_pass)] = _pass; return true; } diff --git a/libethereum/KeyManager.h b/libethcore/KeyManager.h similarity index 96% rename from libethereum/KeyManager.h rename to libethcore/KeyManager.h index 3fcf83c3e..155805c5d 100644 --- a/libethereum/KeyManager.h +++ b/libethcore/KeyManager.h @@ -61,7 +61,7 @@ enum class SemanticPassword class KeyManager { public: - KeyManager(std::string const& _keysFile = getDataDir("ethereum") + "/keys.info"); + KeyManager(std::string const& _keysFile = defaultPath(), std::string const& _secretsPath = SecretStore::defaultPath()); ~KeyManager(); void setKeysFile(std::string const& _keysFile) { m_keysFile = _keysFile; } @@ -99,6 +99,8 @@ public: void kill(h128 const& _id) { kill(address(_id)); } void kill(Address const& _a); + static std::string defaultPath() { return getDataDir("ethereum") + "/keys.info"; } + private: std::string getPassword(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; std::string getPassword(h256 const& _passHash, std::function const& _pass = DontKnowThrow) const; @@ -127,10 +129,10 @@ private: // we have an upgrade strategy. std::string m_password; - SecretStore m_store; + mutable std::string m_keysFile; mutable h128 m_key; mutable h256 m_master; - mutable std::string m_keysFile; + SecretStore m_store; }; } diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index a73f20680..abd0a1adf 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -26,7 +26,8 @@ #include #include #include -#include +#include + using namespace std; using namespace dev; From a7490d16cca1005fc5c371aa18e229f6d62cd99d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 22 May 2015 22:07:31 +0200 Subject: [PATCH 65/70] List and add wallet keys. --- ethkey/KeyAux.h | 90 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index daac72588..3c4a625a4 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -64,22 +64,23 @@ string createPassword(std::string const& _prompt) // return make_pair(ret, hint); } -pair createPassword(KeyManager& _keyManager, std::string const& _prompt) +pair createPassword(KeyManager& _keyManager, std::string const& _prompt, std::string const& _pass = std::string(), std::string const& _hint = std::string()) { - string pass; - while (true) + string pass = _pass; + while (pass.empty()) { pass = getPassword(_prompt); string confirm = getPassword("Please confirm the password by entering it again: "); if (pass == confirm) break; cout << "Passwords were different. Try again." << endl; + pass.clear(); } - string hint; - if (!_keyManager.haveHint(pass)) + string hint = _hint; + if (hint.empty() && !_keyManager.haveHint(pass)) { cout << "Enter a hint to help you remember this password: " << flush; - cin >> hint; + getline(cin, hint); } return make_pair(pass, hint); } @@ -95,6 +96,7 @@ public: ImportBare, ExportBare, RecodeBare, + KillBare, FirstWallet, CreateWallet, List = FirstWallet, @@ -140,6 +142,8 @@ public: m_mode = OperationMode::ExportBare; else if (arg == "--recode-bare") m_mode = OperationMode::RecodeBare; + else if (arg == "--kill-bare") + m_mode = OperationMode::KillBare; else if (arg == "--create-wallet") m_mode = OperationMode::CreateWallet; else if (arg == "--list") @@ -161,7 +165,7 @@ public: m_mode = OperationMode::Recode; else if (arg == "--no-icap") m_icap = false; - else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) + else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) m_inputs.push_back(arg); else return false; @@ -202,10 +206,10 @@ public: if (m_lock.empty()) m_lock = createPassword("Enter a password with which to secure this account: "); auto k = makeKey(); - store.importSecret(k.secret().asBytes(), m_lock); - cout << "Created key " << k.address().abridged() << endl; - cout << "Address: " << k.address().hex() << endl; - cout << "ICAP: " << ICAP(k.address()).encoded() << endl; + h128 u = store.importSecret(k.secret().asBytes(), m_lock); + cout << "Created key " << toUUID(u) << endl; + cout << " Address: " << k.address().hex() << endl; + cout << " ICAP: " << ICAP(k.address()).encoded() << endl; break; } case OperationMode::ImportBare: @@ -244,6 +248,16 @@ public: else cerr << "Couldn't re-encode " << toUUID(u) << "; not found." << endl; } + case OperationMode::KillBare: + for (auto const& i: m_inputs) + { + h128 u = fromUUID(i); + if (u) + store.kill(u); + else + cerr << "Couldn't kill " << toUUID(u) << "; not found." << endl; + } + break; default: break; } } @@ -267,6 +281,55 @@ public: cerr << "Couldn't open wallet. Does it exist?" << endl; exit(-1); } + switch (m_mode) + { + case OperationMode::New: + { + cout << "Enter a description of this key: " << flush; + string info; + getline(cin, info); + + tie(m_lock, m_lockHint) = createPassword(wallet, "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint); + auto k = makeKey(); + h128 u = m_lock.empty() ? wallet.import(k.secret(), m_name) : wallet.import(k.secret(), m_name, m_lock, m_lockHint); + cout << "Created key " << toUUID(u) << endl; + cout << " Name: " << m_name; + if (!m_lockHint.empty()) + cout << " Password hint: " << m_lockHint; + cout << " Address: " << k.address().hex() << endl; + cout << " ICAP: " << ICAP(k.address()).encoded() << endl; + break; + } + case OperationMode::List: + { + vector bare; + vector nonIcap; + for (auto const& u: wallet.store().keys()) + if (Address a = wallet.address(u)) + if (a[0]) + nonIcap.push_back(u); + else + { + std::pair info = wallet.accountDetails()[a]; + cout << toUUID(u) << " " << a.abridged(); + cout << " " << ICAP(a).encoded(); + cout << " " << info.first << endl; + } + else + bare.push_back(u); + for (auto const& u: nonIcap) + if (Address a = wallet.address(u)) + { + std::pair info = wallet.accountDetails()[a]; + cout << toUUID(u) << " " << a.abridged(); + cout << " (Not ICAP) "; + cout << " " << info.first << endl; + } + for (auto const& u: bare) + cout << toUUID(u) << " (Bare)" << endl; + } + default: break; + } } } @@ -284,6 +347,7 @@ public: << " --import-bare [ | , ... ] Import keys from given sources." << endl << " --recode-bare [ | , ... ] Decrypt and re-encrypt given keys." << endl // << " --export-bare [ , ... ] Export given keys." << endl + << " --kill-bare [ , ... ] Delete given keys." << endl << "Secret-store configuration:" << endl << " --secrets-path Specify Web3 secret-store path (default: " << SecretStore::defaultPath() << ")" << endl << endl @@ -303,7 +367,8 @@ public: << " --kdf-param Specify a parameter for the KDF." << endl // << " --cipher Specify cipher to use when encrypting (default: aes-128-ctr)" << endl // << " --cipher-param Specify a parameter for the cipher." << endl - << " --lock Specify password for when encrypting a (the) key." << endl + << " --lock Specify password for when encrypting a (the) key." << endl + << " --hint Specify hint for the --lock password." << endl << endl << "Decryption configuration:" << endl << " --unlock Specify password for a (the) key." << endl @@ -336,6 +401,7 @@ private: string m_masterPassword; strings m_unlocks; string m_lock; + string m_lockHint; bool m_icap = true; /// Creating From db48be76699957f28ddff4be92456f05c1bfc82a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 23 May 2015 10:58:46 +0200 Subject: [PATCH 66/70] Adding and listing wallet keys. --- ethkey/KeyAux.h | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index 3c4a625a4..df2ba5a5a 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -67,17 +67,17 @@ string createPassword(std::string const& _prompt) pair createPassword(KeyManager& _keyManager, std::string const& _prompt, std::string const& _pass = std::string(), std::string const& _hint = std::string()) { string pass = _pass; - while (pass.empty()) - { - pass = getPassword(_prompt); - string confirm = getPassword("Please confirm the password by entering it again: "); - if (pass == confirm) - break; - cout << "Passwords were different. Try again." << endl; - pass.clear(); - } + if (pass.empty()) + while (true) + { + pass = getPassword(_prompt); + string confirm = getPassword("Please confirm the password by entering it again: "); + if (pass == confirm) + break; + cout << "Passwords were different. Try again." << endl; + } string hint = _hint; - if (hint.empty() && !_keyManager.haveHint(pass)) + if (hint.empty() && !pass.empty() && !_keyManager.haveHint(pass)) { cout << "Enter a hint to help you remember this password: " << flush; getline(cin, hint); @@ -97,9 +97,8 @@ public: ExportBare, RecodeBare, KillBare, - FirstWallet, CreateWallet, - List = FirstWallet, + List, New, Import, Export, @@ -112,9 +111,7 @@ public: bool interpretOption(int& i, int argc, char** argv) { string arg = argv[i]; - if (arg == "-n" || arg == "--new") - m_mode = OperationMode::New; - else if (arg == "--wallet-path" && i + 1 < argc) + if (arg == "--wallet-path" && i + 1 < argc) m_walletPath = argv[++i]; else if (arg == "--secrets-path" && i + 1 < argc) m_secretsPath = argv[++i]; @@ -192,7 +189,7 @@ public: else wallet.create(m_masterPassword); } - else if (m_mode < OperationMode::FirstWallet) + else if (m_mode < OperationMode::CreateWallet) { SecretStore store(m_secretsPath); switch (m_mode) @@ -285,17 +282,16 @@ public: { case OperationMode::New: { - cout << "Enter a description of this key: " << flush; - string info; - getline(cin, info); - tie(m_lock, m_lockHint) = createPassword(wallet, "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint); auto k = makeKey(); - h128 u = m_lock.empty() ? wallet.import(k.secret(), m_name) : wallet.import(k.secret(), m_name, m_lock, m_lockHint); + bool usesMaster = m_lock.empty(); + h128 u = usesMaster ? wallet.import(k.secret(), m_name) : wallet.import(k.secret(), m_name, m_lock, m_lockHint); cout << "Created key " << toUUID(u) << endl; - cout << " Name: " << m_name; - if (!m_lockHint.empty()) - cout << " Password hint: " << m_lockHint; + cout << " Name: " << m_name << endl; + if (usesMaster) + cout << " Uses master password." << endl; + else + cout << " Password hint: " << m_lockHint << endl; cout << " Address: " << k.address().hex() << endl; cout << " ICAP: " << ICAP(k.address()).encoded() << endl; break; From 3fcbab1423af5d5dd13bdb94d6c9b760f4fcb98a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 23 May 2015 11:09:39 +0200 Subject: [PATCH 67/70] Fixed #2007 --- alethzero/MainWin.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1dcdcb67f..6a11736a4 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2048,12 +2048,11 @@ void Main::on_killAccount_triggered() auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address h((byte const*)hba.data(), Address::ConstructFromPointer); auto k = m_keyManager.accountDetails()[h]; - if ( - ethereum()->balanceAt(h) != 0 && - QMessageBox::critical(this, QString::fromStdString("Kill Account " + k.first + "?!"), - QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it. It, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n" - "Are you sure you want to continue?"), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) + QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + k.first + "?!"), + QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n" + "Are you sure you want to continue? \r\n If so, type 'YES' to confirm."), + QLineEdit::Normal, "NO"); + if (s != "YES") return; m_keyManager.kill(h); if (m_keyManager.accounts().empty()) From e8b582f3cfb42cd8a09b8cf2620d1583f071be76 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 May 2015 09:28:06 +0100 Subject: [PATCH 68/70] Add secret store test. Remove unneccessary components of scrypt. --- CMakeLists.txt | 3 +- libdevcrypto/SecretStore.cpp | 9 ++++- libdevcrypto/SecretStore.h | 11 ++++-- libscrypt/crypto-scrypt-saltgen.c | 50 ------------------------ libscrypt/crypto_scrypt-hash.c | 44 --------------------- libscrypt/libscrypt.h | 11 ------ test/libdevcrypto/SecretStore.cpp | 64 +++++++++++++++++++++++++++++++ 7 files changed, 81 insertions(+), 111 deletions(-) create mode 100644 test/libdevcrypto/SecretStore.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e7461eb1c..a5c4fe930 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,8 @@ option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF) option(PROFILING "Build in support for profiling" OFF) set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).") -option(MINER "Build the miner component" ON) +option(MINER "Build the CLI miner component" ON) +option(ETHKEY "Build the CLI key manager component" ON) option(SOLIDITY "Build the Solidity language components" ON) option(SERPENT "Build the Serpent language components" ON) option(TOOLS "Build the tools components" ON) diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index c6f9803fa..11ff98bf6 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -165,12 +165,17 @@ void SecretStore::load(std::string const& _keysPath) h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) { cdebug << "Reading" << _file; - js::mValue u = upgraded(contentsString(_file)); + return readKeyContent(contentsString(_file), _deleteFile ? _file : string()); +} + +h128 SecretStore::readKeyContent(std::string const& _content, std::string const& _file) +{ + js::mValue u = upgraded(_content); if (u.type() == js::obj_type) { js::mObject& o = u.get_obj(); auto uuid = fromUUID(o["id"].get_str()); - m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _deleteFile ? _file : string()); + m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _file); return uuid; } else diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index c4e5d5cf7..4474212b1 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -43,6 +43,7 @@ public: bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } + h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } h128 importSecret(bytes const& _s, std::string const& _pass); bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); void kill(h128 const& _uuid); @@ -52,16 +53,20 @@ public: // Clear any cached keys. void clearCache() const; + // Doesn't save(). + h128 readKey(std::string const& _file, bool _deleteFile); + h128 readKeyContent(std::string const& _content, std::string const& _file = std::string()); + + void save(std::string const& _keysPath); + void save() { save(m_path); } + static std::string defaultPath() { return getDataDir("web3") + "/keys"; } private: - void save(std::string const& _keysPath); void load(std::string const& _keysPath); - void save() { save(m_path); } void load() { load(m_path); } static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); static bytes decrypt(std::string const& _v, std::string const& _pass); - h128 readKey(std::string const& _file, bool _deleteFile); mutable std::unordered_map m_cached; std::unordered_map> m_keys; diff --git a/libscrypt/crypto-scrypt-saltgen.c b/libscrypt/crypto-scrypt-saltgen.c index 998a1abcb..e69de29bb 100644 --- a/libscrypt/crypto-scrypt-saltgen.c +++ b/libscrypt/crypto-scrypt-saltgen.c @@ -1,50 +0,0 @@ -#ifndef _MSC_VER -#include -#include -#include -#include -#include - -#ifndef S_SPLINT_S /* Including this here triggers a known bug in splint */ -//#include -#endif - -#define RNGDEV "/dev/urandom" - -int libscrypt_salt_gen(uint8_t *salt, size_t len) -{ - unsigned char buf[len]; - size_t data_read = 0; - int urandom = open(RNGDEV, O_RDONLY); - - if (urandom < 0) - { - return -1; - } - - while (data_read < len) { - ssize_t result = read(urandom, buf + data_read, len - data_read); - - if (result < 0) - { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - - else { - (void)close(urandom); - return -1; - } - } - - data_read += result; - } - - /* Failures on close() shouldn't occur with O_RDONLY */ - (void)close(urandom); - - memcpy(salt, buf, len); - - return 0; -} -#endif diff --git a/libscrypt/crypto_scrypt-hash.c b/libscrypt/crypto_scrypt-hash.c index 4b41007db..e69de29bb 100644 --- a/libscrypt/crypto_scrypt-hash.c +++ b/libscrypt/crypto_scrypt-hash.c @@ -1,44 +0,0 @@ -#include -#include -#include -#include - -#include "b64.h" -#include "libscrypt.h" - -int libscrypt_hash(char *dst, const char *passphrase, uint32_t N, uint8_t r, - uint8_t p) -{ - - int retval; - uint8_t salt[SCRYPT_SALT_LEN]; - uint8_t hashbuf[SCRYPT_HASH_LEN]; - char outbuf[256]; - char saltbuf[256]; - - if(libscrypt_salt_gen(salt, SCRYPT_SALT_LEN) == -1) - { - return 0; - } - - retval = libscrypt_scrypt((const uint8_t*)passphrase, strlen(passphrase), - (uint8_t*)salt, SCRYPT_SALT_LEN, N, r, p, hashbuf, sizeof(hashbuf)); - if(retval == -1) - return 0; - - retval = libscrypt_b64_encode((unsigned char*)hashbuf, sizeof(hashbuf), - outbuf, sizeof(outbuf)); - if(retval == -1) - return 0; - - retval = libscrypt_b64_encode((unsigned char *)salt, sizeof(salt), - saltbuf, sizeof(saltbuf)); - if(retval == -1) - return 0; - - retval = libscrypt_mcf(N, r, p, saltbuf, outbuf, dst); - if(retval != 1) - return 0; - - return 1; -} diff --git a/libscrypt/libscrypt.h b/libscrypt/libscrypt.h index b7141f5f5..889ba13aa 100644 --- a/libscrypt/libscrypt.h +++ b/libscrypt/libscrypt.h @@ -33,17 +33,6 @@ int libscrypt_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, int libscrypt_mcf(uint32_t N, uint32_t r, uint32_t p, const char *salt, const char *hash, char *mcf); -#ifndef _MSC_VER -/* Generates a salt. Uses /dev/urandom/ - */ -int libscrypt_salt_gen(/*@out@*/ uint8_t *rand, size_t len); - -/* Creates a hash of a passphrase using a randomly generated salt */ -/* Returns >0 on success, or 0 for fail */ -int libscrypt_hash(char *dst, const char* passphrase, uint32_t N, uint8_t r, - uint8_t p); -#endif - /* Checks a given MCF against a password */ int libscrypt_check(char *mcf, const char *password); diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp new file mode 100644 index 000000000..1f927db5d --- /dev/null +++ b/test/libdevcrypto/SecretStore.cpp @@ -0,0 +1,64 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file SecretStore.cpp + * @author Gav Wood + * @date 2015 + * Secret store test functions. + */ + +#include +#include +#include +#include "../JsonSpiritHeaders.h" +#include +#include +#include +#include +#include "MemTrie.h" +#include "../TestHelper.h" +using namespace std; +using namespace dev; + +namespace js = json_spirit; + +BOOST_AUTO_TEST_SUITE(KeyStore) + +BOOST_AUTO_TEST_CASE(basic_tests) +{ + string testPath = test::getTestPath(); + + testPath += "/KeyStoreTests"; + + cnote << "Testing Key Store..."; + js::mValue v; + string s = asString(contents(testPath + "/basic_tests.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'KeyStoreTests/basic_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); + js::read_string(s, v); + for (auto& i: v.get_obj()) + { + cnote << i.first; + js::mObject& o = i.second.get_obj(); + SecretStore store("."); + h128 u = store.readKeyContent(js::write_string(o["json"], false)); + cdebug << "read uuid" << u; + bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); + cdebug << "got secret" << toHex(s); + BOOST_REQUIRE_EQUAL(toHex(s), o["priv"].get_str()); + } +} + +BOOST_AUTO_TEST_SUITE_END() From 6281c11534c97e719ff228ee810d9c710b79a882 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 25 May 2015 11:49:38 +0200 Subject: [PATCH 69/70] Sort keywords and add some reserved keywords. --- libsolidity/Token.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 1435dcc57..8a373da34 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -142,34 +142,34 @@ namespace solidity K(Delete, "delete", 0) \ \ /* Keywords */ \ + K(Anonymous, "anonymous", 0) \ K(Break, "break", 0) \ K(Const, "constant", 0) \ - K(Anonymous, "anonymous", 0) \ K(Continue, "continue", 0) \ K(Contract, "contract", 0) \ K(Default, "default", 0) \ K(Do, "do", 0) \ K(Else, "else", 0) \ + K(Enum, "enum", 0) \ K(Event, "event", 0) \ K(External, "external", 0) \ - K(Is, "is", 0) \ - K(Indexed, "indexed", 0) \ K(For, "for", 0) \ K(Function, "function", 0) \ K(If, "if", 0) \ + K(Indexed, "indexed", 0) \ + K(Internal, "internal", 0) \ K(Import, "import", 0) \ + K(Is, "is", 0) \ K(Mapping, "mapping", 0) \ K(Modifier, "modifier", 0) \ K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Internal, "internal", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ K(Var, "var", 0) \ K(While, "while", 0) \ - K(Enum, "enum", 0) \ \ /* Ether subdenominations */ \ K(SubWei, "wei", 0) \ @@ -304,15 +304,21 @@ namespace solidity T(Identifier, NULL, 0) \ \ /* Keywords reserved for future. use*/ \ - T(String, "string", 0) \ + K(As, "as", 0) \ K(Case, "case", 0) \ + K(Catch, "catch", 0) \ + K(Final, "final", 0) \ + K(Let, "let", 0) \ + K(Match, "match", 0) \ + K(Of, "of", 0) \ + K(Relocatable, "relocatable", 0) \ + T(String, "string", 0) \ K(Switch, "switch", 0) \ K(Throw, "throw", 0) \ K(Try, "try", 0) \ - K(Catch, "catch", 0) \ - K(Using, "using", 0) \ K(Type, "type", 0) \ K(TypeOf, "typeof", 0) \ + K(Using, "using", 0) \ /* Illegal token - not able to scan. */ \ T(Illegal, "ILLEGAL", 0) \ \ From 4251276cb304c178235691a3815836231adda795 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 May 2015 19:10:50 +0100 Subject: [PATCH 70/70] Fix mining. Again. --- libethash/internal.c | 2 +- libethcore/Ethash.cpp | 8 ++++++-- libethcore/EthashAux.cpp | 6 ++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libethash/internal.c b/libethash/internal.c index e881e0c7b..2a12163f7 100644 --- a/libethash/internal.c +++ b/libethash/internal.c @@ -368,7 +368,7 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f) if ((fd = ethash_fileno(ret->file)) == -1) { return false; } - mmapped_data= mmap( + mmapped_data = mmap( NULL, (size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE, PROT_READ | PROT_WRITE, diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 24a6ab41e..60585a162 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -142,8 +142,12 @@ void Ethash::CPUMiner::workLoop() WorkPackage w = work(); EthashAux::FullType dag; - while (!shouldStop() && !(dag = EthashAux::full(w.seedHash, true))) - this_thread::sleep_for(chrono::milliseconds(500)); + while (!shouldStop() && !dag) + { + while (!shouldStop() && EthashAux::computeFull(w.seedHash, true) != 100) + this_thread::sleep_for(chrono::milliseconds(500)); + dag = EthashAux::full(w.seedHash, false); + } h256 boundary = w.boundary; unsigned hashCount = 1; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index a94c1237d..06da22f98 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -133,7 +133,9 @@ bytesConstRef EthashAux::LightAllocation::data() const EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb) { +// cdebug << "About to call ethash_full_new..."; full = ethash_full_new(_light, _cb); +// cdebug << "Called OK."; if (!full) BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new()")); } @@ -170,9 +172,9 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing if (_createIfMissing || computeFull(_seedHash, false) == 100) { s_dagCallback = _f; - cnote << "Loading from libethash..."; +// cnote << "Loading from libethash..."; ret = make_shared(l->light, dagCallbackShim); - cnote << "Done loading."; +// cnote << "Done loading."; DEV_GUARDED(get()->x_fulls) get()->m_fulls[_seedHash] = get()->m_lastUsedFull = ret;