mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-20 17:54:38 +00:00
Increase constant-time properties of from_repr/from_bytes
It's still not perfect, as it's Option -> CtOption which requires an unwrap_or, but...
This commit is contained in:
parent
a4c2f71610
commit
41eaa1b124
1 changed files with 16 additions and 12 deletions
|
@ -32,6 +32,12 @@ use dalek::{
|
||||||
use ff::{Field, PrimeField, FieldBits, PrimeFieldBits};
|
use ff::{Field, PrimeField, FieldBits, PrimeFieldBits};
|
||||||
use group::{Group, GroupEncoding, prime::PrimeGroup};
|
use group::{Group, GroupEncoding, prime::PrimeGroup};
|
||||||
|
|
||||||
|
fn choice(value: bool) -> Choice {
|
||||||
|
let bit = value as u8;
|
||||||
|
debug_assert_eq!(bit | 1, 1);
|
||||||
|
Choice::from(bit)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! deref_borrow {
|
macro_rules! deref_borrow {
|
||||||
($Source: ident, $Target: ident) => {
|
($Source: ident, $Target: ident) => {
|
||||||
impl Deref for $Source {
|
impl Deref for $Source {
|
||||||
|
@ -160,7 +166,7 @@ impl Field for Scalar {
|
||||||
fn square(&self) -> Self { *self * self }
|
fn square(&self) -> Self { *self * self }
|
||||||
fn double(&self) -> Self { *self + self }
|
fn double(&self) -> Self { *self + self }
|
||||||
fn invert(&self) -> CtOption<Self> {
|
fn invert(&self) -> CtOption<Self> {
|
||||||
CtOption::new(Self(self.0.invert()), Choice::from(1 as u8))
|
CtOption::new(Self(self.0.invert()), self.is_zero())
|
||||||
}
|
}
|
||||||
fn sqrt(&self) -> CtOption<Self> { unimplemented!() }
|
fn sqrt(&self) -> CtOption<Self> { unimplemented!() }
|
||||||
fn is_zero(&self) -> Choice { self.0.ct_eq(&DScalar::zero()) }
|
fn is_zero(&self) -> Choice { self.0.ct_eq(&DScalar::zero()) }
|
||||||
|
@ -177,11 +183,9 @@ impl PrimeField for Scalar {
|
||||||
const NUM_BITS: u32 = 253;
|
const NUM_BITS: u32 = 253;
|
||||||
const CAPACITY: u32 = 252;
|
const CAPACITY: u32 = 252;
|
||||||
fn from_repr(bytes: [u8; 32]) -> CtOption<Self> {
|
fn from_repr(bytes: [u8; 32]) -> CtOption<Self> {
|
||||||
let scalar = DScalar::from_canonical_bytes(bytes).map(|x| Scalar(x));
|
let scalar = DScalar::from_canonical_bytes(bytes);
|
||||||
CtOption::new(
|
// TODO: This unwrap_or isn't constant time, yet do we have an alternative?
|
||||||
scalar.unwrap_or(Scalar::zero()),
|
CtOption::new(Scalar(scalar.unwrap_or(DScalar::zero())), choice(scalar.is_some()))
|
||||||
Choice::from(if scalar.is_some() { 1 } else { 0 })
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn to_repr(&self) -> [u8; 32] { self.0.to_bytes() }
|
fn to_repr(&self) -> [u8; 32] { self.0.to_bytes() }
|
||||||
|
|
||||||
|
@ -237,6 +241,8 @@ macro_rules! dalek_group {
|
||||||
|
|
||||||
impl Group for $Point {
|
impl Group for $Point {
|
||||||
type Scalar = Scalar;
|
type Scalar = Scalar;
|
||||||
|
// Ideally, this would be cryptographically secure, yet that's not a bound on the trait
|
||||||
|
// k256 also does this
|
||||||
fn random(rng: impl RngCore) -> Self { &$BASEPOINT_TABLE * Scalar::random(rng) }
|
fn random(rng: impl RngCore) -> Self { &$BASEPOINT_TABLE * Scalar::random(rng) }
|
||||||
fn identity() -> Self { Self($DPoint::identity()) }
|
fn identity() -> Self { Self($DPoint::identity()) }
|
||||||
fn generator() -> Self { $BASEPOINT_POINT }
|
fn generator() -> Self { $BASEPOINT_POINT }
|
||||||
|
@ -248,12 +254,10 @@ macro_rules! dalek_group {
|
||||||
type Repr = [u8; 32];
|
type Repr = [u8; 32];
|
||||||
|
|
||||||
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
if let Some(point) = $DCompressed(*bytes).decompress() {
|
let decompressed = $DCompressed(*bytes).decompress();
|
||||||
if $torsion_free(point) {
|
// TODO: Same note on unwrap_or as above
|
||||||
return CtOption::new($Point(point), Choice::from(1));
|
let point = decompressed.unwrap_or($DPoint::identity());
|
||||||
}
|
CtOption::new($Point(point), choice(decompressed.is_some()) & choice($torsion_free(point)))
|
||||||
}
|
|
||||||
CtOption::new($Point::identity(), Choice::from(0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
|
Loading…
Reference in a new issue