Как ускорить подсчёт sha256?

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
Пытаюсь решить задачку...
Есть 2 байтовых массива + нужно подобрать третий согласно условий.
Набросал кодец, и всё хорошо, вычисляет где-то 2-5 секунд нужное значение.
Но, меня уж очень беспокоит, можно ли как-то усовершенствовать, чтобы сделать хотя бы в 10 раз быстрее.
Специалисты, помогите ускорить код пожалуйста....

C#:
long outdata = 0;
byte[] data1 = new byte[]{ 0, 0, 144, 134, 3 };
byte[] data2 = new byte[]{ 131, 20, 26, 31, 187, 62, 81, 252, 159, 53, 196};

System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
project.SendInfoToLog("Старт");
timer.Start();
for(long i = 0; i<long.MaxValue;i++) {
    byte[] data3 = BitConverter.GetBytes(i);
    byte[] rv = new byte[data1.Length + data2.Length + data3.Length];
    System.Buffer.BlockCopy(data1, 0, rv, 0, data1.Length);
    System.Buffer.BlockCopy(data2, 0, rv, data1.Length, data2.Length);
    System.Buffer.BlockCopy(data3, 0, rv, data1.Length + data2.Length, data3.Length);

    int[] data4 = new int[6];
     using(var sha256 = System.Security.Cryptography.SHA256.Create()) { 
        byte[] m = sha256.ComputeHash(rv);
        string data5 = BitConverter.ToString(m).Replace("-", string.Empty).Remove(5);
        for(int j=0;j<data5.Length;j++) {
            data4[j] = int.Parse(data5[j].ToString(), System.Globalization.NumberStyles.HexNumber);
        } 
    }
    int sum = data4.Sum() - data4.Last();
    if(sum == 0 && data4.Last() < 2) {
        outdata = i;
        break;
    }
}
timer.Stop();
project.SendInfoToLog(string.Format(@"End. {0:mm}:{0:ss}.{0:fff} {1}",timer.Elapsed, outdata ),true);

Из того, что сам пытался - переписал код под IEnumerable и yield чтобы вместо for дёргать в AsParallel - это в свою очередь повысило скорость в 2 раза.
Но, мне кажется, что я что-то упускаю...

Пробовал сгенерировать последовательность, например от 0 до 10 000 000 и пытался дёргать через for, AsParallel - в результате скорость возросла с 2-5 секунд до 16-20 секунд (хотя, мне казалось, что если поместить значения уже в ОЗУ, то должно было бы работать быстрее...).

Что можно ещё попробовать?
Накидайте вариантов пожалуйста....

Скриншот того, что уже есть. Можно быстрее? Если можно - как?

83872



P.S.
Избавился от BitConverter.ToString(m).Replace("-", string.Empty).Remove(5); - ещё чуток подкрутил производительность... Надеялся, что как-то побольше результат будет от этого... В итоге - почти не заметно...

C#:
byte[] m = sha256.ComputeHash(bytes).ToArray();
if(m[0] == m[1] && m[1] == 0 && m[2] < 16) return true;
return false;
83875


P.S. Ещё чуток подшаманил..
Оказалось, что переводил в hash16 результат написаной на коленке функцией, и она получается работала медленнее, чем BitConverter. Пришлось вернуть его обратно (в момент вывода результата). 3 000 000 было 4 секунды, сейчас 3 200 000 считает за 2.8 секунды :-) Ещё чего-то не хватает... Продолжаю шаманить...
BitConverter.ToString(bytes).Replace("-", string.Empty).ToLower();
83877


P.S. Оказалось что в конструкции AsParallel есть опция, с которой данную работу делает быстрее, чем без нее. Хотя... Также думал о том, что мол задача на 1кк элементов должна бы заставить LINQ использовать параллелизм (чтобы ускорить), но он оказывается думает иначе и без опции видимо считает через раз (один раз параллельно, другой - последовательно).
C#:
// Код без опции WithExecutionMode - медленнее
//return m.AsParallel().WithDegreeOfParallelism(count_processor)
// .Where(x => x.CheckHash(nonce)).First().ToHex16();

// Остановился на этом...
return m.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism).WithDegreeOfParallelism(count_processor)
      .Where(x => x.CheckHash(nonce)).First().ToHex16();
P.S. И вот наконец-то я нашел ту волшебную таблетку, которую искал.
Необходимо создавать:
C#:
private static readonly SHA256 sha256f = SHA256.Create();
И потом дёргать его...
C#:
byte[] m = sha256f.ComputeHash(bytes);
if(m[0] == m[1] && m[1] == 0 && m[2] < 16)
    return true;
return false;
И на выходе 3 360 000 хешей за 2.68 (если гадать последовательно):
83878

83880


Или чуть больше времени если заполнять nonce используя рандом:
83879


В итоге, на сколько я понял продолжать копать дальше нет смысла.
Оптимальный вариант использовать Enumerable, AsParallel с включеной опцией параллелизма, использовать yield с целью замены for. Также штуки которые приходится создавать несколько раз - создаем один раз в виде статического поля. И... Да здравствует производительность...
 
Последнее редактирование:
  • Спасибо
Реакции: RoyalBank

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 310
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
https://github.com/dotnet/BenchmarkDotNet
тут автор бенча как-раз гоняет тесты, используя и расчет sha256
дерни там сорс
Спасибо, благодаря Вашей ссылочке подглядел здесь что можно создать статическое поле, чтобы не создавать его миллион раз в каждом потоке.
Это помогло (на сколько я понял) ускорить ещё данный костыль :-)
 

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
Ну и вопросы в разделе новичков...

Может переписать сразу на Rust C? :bw:
 
  • Спасибо
Реакции: devffy, zennoman и BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
Рано я обрадовался....
Короче шаманил шаманил - нашаманил....
И вот, вроде всё считает, и всё красиво, но результаты на выходе не валидные.
Сутки убил на то, чтобы понять, что создание SHA256 используя статический объект - ПОТОКОНЕБЕЗОПАСНО.
Нельзя так делать... Придётся искать как реализовать без локов эту шляпу потокобезопасно...

private static readonly SHA256 sha256f = SHA256.Create();


Ну и вопросы в разделе новичков...
Не хочу нарушать правила форума - но для оффтопа тема не годится, а в какой правильно раздел определять темы - за 5 лет ещё не определился, так как когда не знаю как решить проблему, то кажется что тема как раз для новичков.
 

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 310
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

код и первого поста дает валидные ключи?
вопрос просто в типе порядка байт, big endian или little endian
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
код и первого поста дает валидные ключи?
вопрос просто в типе порядка байт, big endian или little endian
Без статического SHA256.Create(); - данные валидные (без изменения порядка байт) - сгенерированные 8 байт, которые я ищу могут быть любыми, просто чтобы иметь возможность измерять результат я специально пытаюсь выполнять одну и ту же работу от 0 до максимума например).
Суть в получении sha256 который будет начинаться на 5 нулей спереди используя входящие данные + подобранный nonce (который я и подбираю кодом выше).

Так что пока вопрос открытый - 1 000 000 итераций sha256 в секунду меня не устраивает, надо хотя бы 2 000 000 - 5 000 000 в секунду.

P.S. Нужно проверить.... Видимо у меня где-то ещё и здесь ошибка: порядка байт, big endian или little endian
 
Последнее редактирование:

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 310
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

ну тут такие пути:
1. читать интеловскую/амд доку (если у тебя камень интеловский/амд) смотреть спецификацию по нему и искать реализацию крипто функций поl него. как-то помню под avx-256 искал, находил (вектора нужно было ворочать)
+ github
найти, скомпилить и подключить к шарпу как ансейф код и дергать из него функцию

2. либа OpenSSl по умолчанию юзает хардварную функцию проца sha-2 семейства если она доступна

3. Гонять на гпу, смотреть hashcat


п.с. ты че там jwt/hsw токены h*** брутишь?
эт где такая валидация....
int sum = data4.Sum() - data4.Last();
if(sum == 0 && data4.Last() < 2)

п.с и у тебя на входе 1 массив. не знаю зачем ты его порезал на два.
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
ну тут такие пути:
1. читать интеловскую/амд доку (если у тебя камень интеловский/амд) смотреть спецификацию по нему и искать реализацию крипто функций поl него. как-то помню под avx-256 искал, находил (вектора нужно было ворочать)
https://en.wikipedia.org/wiki/Intel_SHA_extensions
https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/sha-256-implementations-paper.pdf
+ github
найти, скомпилить и подключить к шарпу как ансейф код и дергать из него функцию

2. либа OpenSSl по умолчанию юзает хардварную функцию проца sha-2 семейства если она доступна

3. Гонять на гпу, смотреть hashcat
https://hashcat.net/hashcat/#features-algos


п.с. ты че там jwt/hsw токены h*** брутишь?
эт где такая валидация....
int sum = data4.Sum() - data4.Last();
if(sum == 0 && data4.Last() < 2)

п.с и у тебя на входе 1 массив. не знаю зачем ты его порезал на два.
Спасибо за помощь!
Изучу ещё и эти материалы!
Сейчас ещё раз пересматриваю все свои решения чтобы понять где я ошибся (по всей видимости в меня все ок, а в коде который писал для данной темы - где-то ошибка, из-за чего в итоге все мои наблюдения не верны...).

п.с и у тебя на входе 1 массив. не знаю зачем ты его порезал на два.
На скриншотах первое значение - это long в шестнадцатиричном формате, а второе - это второй входящий массив байт размером 8 в шестнадцатиричном формате.
 
Последнее редактирование:

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)