mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-14 06:59:24 +00:00
Dedicated crate for the Schnorr contract
This commit is contained in:
68
networks/ethereum/schnorr/src/public_key.rs
Normal file
68
networks/ethereum/schnorr/src/public_key.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use subtle::Choice;
|
||||
use group::ff::PrimeField;
|
||||
use k256::{
|
||||
elliptic_curve::{
|
||||
ops::Reduce,
|
||||
point::{AffineCoordinates, DecompressPoint},
|
||||
},
|
||||
AffinePoint, ProjectivePoint, Scalar, U256 as KU256,
|
||||
};
|
||||
|
||||
/// A public key for the Schnorr Solidity library.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct PublicKey {
|
||||
A: ProjectivePoint,
|
||||
x_coordinate: [u8; 32],
|
||||
}
|
||||
|
||||
impl PublicKey {
|
||||
/// Construct a new `PublicKey`.
|
||||
///
|
||||
/// This will return None if the provided point isn't eligible to be a public key (due to
|
||||
/// bounds such as parity).
|
||||
#[must_use]
|
||||
pub fn new(A: ProjectivePoint) -> Option<PublicKey> {
|
||||
let affine = A.to_affine();
|
||||
|
||||
// Only allow even keys to save a word within Ethereum
|
||||
if bool::from(affine.y_is_odd()) {
|
||||
None?;
|
||||
}
|
||||
|
||||
let x_coordinate = affine.x();
|
||||
// Return None if the x-coordinate isn't mutual to both fields
|
||||
// While reductions shouldn't be an issue, it's one less headache/concern to have
|
||||
// The trivial amount of public keys this makes non-representable aren't a concern
|
||||
if <Scalar as Reduce<KU256>>::reduce_bytes(&x_coordinate).to_repr() != x_coordinate {
|
||||
None?;
|
||||
}
|
||||
|
||||
Some(PublicKey { A, x_coordinate: x_coordinate.into() })
|
||||
}
|
||||
|
||||
/// The point for this public key.
|
||||
#[must_use]
|
||||
pub fn point(&self) -> ProjectivePoint {
|
||||
self.A
|
||||
}
|
||||
|
||||
/// The Ethereum representation of this public key.
|
||||
#[must_use]
|
||||
pub fn eth_repr(&self) -> [u8; 32] {
|
||||
// We only encode the x-coordinate due to fixing the sign of the y-coordinate
|
||||
self.x_coordinate
|
||||
}
|
||||
|
||||
/// Construct a PublicKey from its Ethereum representation.
|
||||
// This wouldn't be possible if the x-coordinate had been reduced
|
||||
#[must_use]
|
||||
pub fn from_eth_repr(repr: [u8; 32]) -> Option<Self> {
|
||||
let x_coordinate = repr;
|
||||
|
||||
let y_is_odd = Choice::from(0);
|
||||
let A_affine =
|
||||
Option::<AffinePoint>::from(AffinePoint::decompress(&x_coordinate.into(), y_is_odd))?;
|
||||
let A = ProjectivePoint::from(A_affine);
|
||||
Some(PublicKey { A, x_coordinate })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user