# 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 ```