# EVM GOST Lib
`evm-gost-lib` - это [Solidity](https://soliditylang.org/) библиотека для работы с ГОСТ алгоритмами криптографии.
Библиотека работает совместно с precompile контрактами в [go-ethereum](https://github.com/ethereum/go-ethereum/).
PR с расширением функционала go-ethereum: [emcpow2/go-ethereum/pull/1](https://github.com/emcpow2/go-ethereum/pull/1).
## Возможности
1. On-chain проверка ЭЦП по ГОСТ 34.10.
2. On-chain вычисление хэш кода по ГОСТ 34.11
Благодаря исполнению алгоритмов в виде precompile контрактов, расход газа сопоставим в функциями `keccak256` и `ecrecover`.
Что открывает возможности по прикладному применению ГОСТ алгоритмов криптографии.
## Сферы применения
1. Подпись и проверка простых сообщений(текст).
2. Подпись и проверки структурированных сообщений [EIP-712](https://eips.ethereum.org/EIPS/eip-712).
3. Account Abstraction [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) - смарт контракт аккаунты основанные на ГОСТ алгоритмах шифрования.
## Пример использования
Пример ниже искусственный, но позволяет оценить библиотеку в применении.
При создании контракта, передается открытый ключ владельца. Этот ключ в дальнейшем используется для проверки подлинности ЭЦП.
Для вызова mint нужно подтвердить права. Для этого алгоритм ожидает передачи `signature`(ЭЦП) и сообщения.
Если сообщение подписано ключом и соответствует предоставленной подписи, то вызов `mint` проходит успешно.
Варианты использования этим не ограничиваются, можно встраивать в любой программу смарт контракта.
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Gost } from "evm-gost-lib";
contract MyToken is ERC20 {
bytes storage ownerPubKey;
constructor(bytes calldata ownerPubKey_) ERC20("MyToken", "MTK") {
ownerPubKey = ownerPubKey_;
}
function mint(address to, uint256 amount, bytes calldata message, bytes calldata signature) public {
require(Gost.gost3410Verify(message, ownerPubKey, signature), "Provided signature is not valid.);
_mint(to, amount);
}
}
```
## Установка
https://github.com/emcpow2/go-ethereum/pull/1
Сделайте клон репозитория, установите [Node.js](https://nodejs.org/en) v20.
## Generating GOST 34.10 256bit keys with OpenSSL
### Generate certificate, private key and public key
A command below generates a GOST private key and a certificate.
```console
$ openssl req -x509 -newkey gost2012_256 -pkeyopt paramset:A -nodes -keyout cert.key -out cert.pem
```
Extract public key using the following command.
```console
$ openssl x509 -in cert.pem -noout -pubkey > pubkey.pem
```
This will create the following files:
1. `cert.pem` - the certificate. It is a container for public key.
2. `cert.key` - pem encoded private key.
3. `pubkey.pem` - pem encoded public key.
### Other forms of public key
In order to use public key programmatically, we need a binary form of public key.
Public key is a point in 2-dimension space. X and Y coordinates of the point are 256 bit keys. Total size of public key 64 bytes.
We can look on public key in certificate with the command.
```console
$ openssl x509 -text -in cert.pem
Subject Public Key Info:
Public Key Algorithm: GOST R 34.10-2012 with 256 bit modulus
Public key:
X:400070DEAC700554FA7C1DE06F69A8D8741C0A992FC7FBAEA2574828E046ECAF
Y:722E184F7257C34489D7F12324DB952B9EAC9D97BCC610F3248239C8B08F872E
Parameter set: id-GostR3410-2001-CryptoPro-A-ParamSet
```
Another way to extract public key is `openssl asn1parse` utility.
```console
$ openssl asn1parse -strictpem -strparse 35 -in pubkey.pem
0:d=0 hl=2 l= 64 prim: OCTET STRING [HEX DUMP]:AFEC46E0284857A2AEFBC72F990A1C74D8A8696FE01D7CFA540570ACDE7000402E878FB0C8398224F310C6BC979DAC9E2B95DB2423F1D78944C357724F182E72
```
With a closer look, you may notice hex encoded `asn1parse` contains public key coordinate, but byte order is reversed.
## GOST 34.11 256bit hash with OpenSSL
```console
$ echo "Hello, World!" > message.txt
$ openssl dgst -md_gost12_256 message.txt
md_gost12_256(message.txt)= 5d7de75ec593ba16e44d134a239d7582fb4f7df02c607524a72258d69f2146a1
```
Take into account that `message.txt` has `\n` symbol at the end, so that message is `Hello, World!\n`. Message size is 14 bytes.
## GOST 34.10 signatures with OpenSSL
To sign a message with openssl use the following command:
```console
$ openssl dgst -md_gost12_256 -sign cert.key -out message.txt.gost12 message.txt
```
Resulting `message.txt.gost12` will contain binary signature. Signature size is 64 bytes.
Signature verification:
```console
$ openssl dgst -md_gost12_256 -verify pubkey.pem -signature message.txt.gost12 message.txt
Verified OK
```