mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
ethereum: implement schnorr verification contract deployment and related crypto (#36)
* basic schnorr verify working * add schnorr-verify as submodule * remove previous code * Misc Ethereum work which will probably be disregarded * add ecrecover hack test, worksgit add src/ * merge w develop * starting w/ rust-web3 * trying to use ethers * deploy_schnorr_verifier_contract finally working * modify EthereumHram to use 27/28 for point parity * updated address calc, solidity schnorr verify now working * add verify failure to test * update readme * move ethereum/ to coins/ * un fmt coins/monero * update .gitmodules * fix cargo paths * fix coins/monero * add #[allow(non_snake_case)] * un-fmt stuff * move crypto to coins/ethereum * move unit tests to ethereum/tests * remove js, build w ethers * update .gitignore * address comments * add q != 0 check * update contract param order * update contract license to AGPL * update ethereum-serai license to GPL and fmt * GPLv3 for ethereum-serai * AGPLv3 for ethereum-serai * actually fix license Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
This commit is contained in:
60
coins/ethereum/tests/contract.rs
Normal file
60
coins/ethereum/tests/contract.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use ethereum_serai::contract::{call_verify, deploy_schnorr_verifier_contract};
|
||||
use ethers::{prelude::*, utils::Anvil};
|
||||
use std::{convert::TryFrom, sync::Arc, time::Duration};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_deploy_contract() {
|
||||
let anvil = Anvil::new().spawn();
|
||||
let wallet: LocalWallet = anvil.keys()[0].clone().into();
|
||||
let provider =
|
||||
Provider::<Http>::try_from(anvil.endpoint()).unwrap().interval(Duration::from_millis(10u64));
|
||||
let client = Arc::new(SignerMiddleware::new(provider, wallet));
|
||||
|
||||
let _contract = deploy_schnorr_verifier_contract(client).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_ecrecover_hack() {
|
||||
use ethereum_serai::crypto;
|
||||
use ethers::utils::keccak256;
|
||||
use frost::{
|
||||
algorithm::Schnorr,
|
||||
curve::Secp256k1,
|
||||
tests::{algorithm_machines, key_gen, sign},
|
||||
};
|
||||
use k256::elliptic_curve::bigint::ArrayEncoding;
|
||||
use k256::{Scalar, U256};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let anvil = Anvil::new().spawn();
|
||||
let wallet: LocalWallet = anvil.keys()[0].clone().into();
|
||||
let provider =
|
||||
Provider::<Http>::try_from(anvil.endpoint()).unwrap().interval(Duration::from_millis(10u64));
|
||||
let chain_id = provider.get_chainid().await.unwrap();
|
||||
let client = Arc::new(SignerMiddleware::new(provider, wallet));
|
||||
|
||||
let keys = key_gen::<_, Secp256k1>(&mut OsRng);
|
||||
let group_key = keys[&1].group_key();
|
||||
|
||||
const MESSAGE: &'static [u8] = b"Hello, World!";
|
||||
let hashed_message = keccak256(MESSAGE);
|
||||
let chain_id = U256::from(Scalar::from(chain_id.as_u32()));
|
||||
|
||||
let full_message = &[chain_id.to_be_byte_array().as_slice(), &hashed_message].concat();
|
||||
|
||||
let sig = sign(
|
||||
&mut OsRng,
|
||||
algorithm_machines(&mut OsRng, Schnorr::<Secp256k1, crypto::EthereumHram>::new(), &keys),
|
||||
full_message,
|
||||
);
|
||||
let mut processed_sig =
|
||||
crypto::process_signature_for_contract(hashed_message, &sig.R, sig.s, &group_key, chain_id);
|
||||
|
||||
let contract = deploy_schnorr_verifier_contract(client).await.unwrap();
|
||||
call_verify(&contract, &processed_sig).await.unwrap();
|
||||
|
||||
// test invalid signature fails
|
||||
processed_sig.message[0] = 0;
|
||||
let res = call_verify(&contract, &processed_sig).await;
|
||||
assert!(res.is_err());
|
||||
}
|
||||
80
coins/ethereum/tests/crypto.rs
Normal file
80
coins/ethereum/tests/crypto.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use ethereum_serai::crypto::*;
|
||||
use frost::curve::Secp256k1;
|
||||
use k256::{
|
||||
elliptic_curve::{bigint::ArrayEncoding, ops::Reduce, sec1::ToEncodedPoint},
|
||||
ProjectivePoint, Scalar, U256,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_ecrecover() {
|
||||
use k256::ecdsa::{
|
||||
recoverable::Signature,
|
||||
signature::{Signer, Verifier},
|
||||
SigningKey, VerifyingKey,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let private = SigningKey::random(&mut OsRng);
|
||||
let public = VerifyingKey::from(&private);
|
||||
|
||||
const MESSAGE: &'static [u8] = b"Hello, World!";
|
||||
let sig: Signature = private.sign(MESSAGE);
|
||||
public.verify(MESSAGE, &sig).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
ecrecover(hash_to_scalar(MESSAGE), sig.as_ref()[64], *sig.r(), *sig.s()).unwrap(),
|
||||
address(&ProjectivePoint::from(public))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signing() {
|
||||
use frost::{
|
||||
algorithm::Schnorr,
|
||||
tests::{algorithm_machines, key_gen, sign},
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let keys = key_gen::<_, Secp256k1>(&mut OsRng);
|
||||
let _group_key = keys[&1].group_key();
|
||||
|
||||
const MESSAGE: &'static [u8] = b"Hello, World!";
|
||||
|
||||
let _sig = sign(
|
||||
&mut OsRng,
|
||||
algorithm_machines(&mut OsRng, Schnorr::<Secp256k1, EthereumHram>::new(), &keys),
|
||||
MESSAGE,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ecrecover_hack() {
|
||||
use frost::{
|
||||
algorithm::Schnorr,
|
||||
tests::{algorithm_machines, key_gen, sign},
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let keys = key_gen::<_, Secp256k1>(&mut OsRng);
|
||||
let group_key = keys[&1].group_key();
|
||||
let group_key_encoded = group_key.to_encoded_point(true);
|
||||
let group_key_compressed = group_key_encoded.as_ref();
|
||||
let group_key_x = Scalar::from_uint_reduced(U256::from_be_slice(&group_key_compressed[1 .. 33]));
|
||||
|
||||
const MESSAGE: &'static [u8] = b"Hello, World!";
|
||||
let hashed_message = keccak256(MESSAGE);
|
||||
let chain_id = U256::from(Scalar::ONE);
|
||||
|
||||
let full_message = &[chain_id.to_be_byte_array().as_slice(), &hashed_message].concat();
|
||||
|
||||
let sig = sign(
|
||||
&mut OsRng,
|
||||
algorithm_machines(&mut OsRng, Schnorr::<Secp256k1, EthereumHram>::new(), &keys),
|
||||
full_message,
|
||||
);
|
||||
|
||||
let (sr, er) =
|
||||
preprocess_signature_for_ecrecover(hashed_message, &sig.R, sig.s, &group_key, chain_id);
|
||||
let q = ecrecover(sr, group_key_compressed[0] - 2, group_key_x, er).unwrap();
|
||||
assert_eq!(q, address(&sig.R));
|
||||
}
|
||||
2
coins/ethereum/tests/mod.rs
Normal file
2
coins/ethereum/tests/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod contract;
|
||||
mod crypto;
|
||||
Reference in New Issue
Block a user