1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::{util::*, Token};
use bls12_381_plus::Scalar;
use core::convert::TryFrom;
use ff::Field;
use rand_core::*;
use serde::{Deserialize, Serialize};
use subtle::{Choice, ConstantTimeEq, CtOption};
use zeroize::Zeroize;
#[derive(Clone, Debug, Eq, Deserialize, Serialize, Zeroize)]
#[zeroize(drop)]
pub struct SecretKey {
pub(crate) w: Scalar,
pub(crate) x: Scalar,
pub(crate) y: Scalar,
}
impl Default for SecretKey {
fn default() -> Self {
Self {
w: Scalar::zero(),
x: Scalar::zero(),
y: Scalar::zero(),
}
}
}
impl From<&[u8; SecretKey::BYTES]> for SecretKey {
fn from(data: &[u8; Self::BYTES]) -> Self {
Self::from_bytes(data).unwrap()
}
}
impl PartialEq for SecretKey {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).unwrap_u8() == 1
}
}
impl ConstantTimeEq for SecretKey {
fn ct_eq(&self, rhs: &Self) -> Choice {
self.x.ct_eq(&rhs.x) & self.y.ct_eq(&rhs.y) & self.w.ct_eq(&rhs.w)
}
}
#[cfg(feature = "wasm")]
wasm_slice_impl!(SecretKey);
impl SecretKey {
pub const BYTES: usize = 96;
pub fn new(mut rng: impl RngCore + CryptoRng) -> Self {
Self {
w: Scalar::random(&mut rng),
x: Scalar::random(&mut rng),
y: Scalar::random(&mut rng),
}
}
pub fn hash(data: &[u8]) -> Self {
let mut values = [Scalar::zero(); 3];
hash_to_scalars(&[data], &mut values);
Self {
w: values[0],
x: values[1],
y: values[2],
}
}
pub fn to_bytes(&self) -> [u8; Self::BYTES] {
let mut out = [0u8; Self::BYTES];
out[..32].copy_from_slice(&self.w.to_bytes()[..]);
out[32..64].copy_from_slice(&self.x.to_bytes()[..]);
out[64..].copy_from_slice(&self.y.to_bytes()[..]);
out
}
pub fn from_bytes(data: &[u8; Self::BYTES]) -> CtOption<Self> {
let ww = Scalar::from_bytes(&<[u8; 32]>::try_from(&data[..32]).unwrap());
let xx = Scalar::from_bytes(&<[u8; 32]>::try_from(&data[32..64]).unwrap());
let yy = Scalar::from_bytes(&<[u8; 32]>::try_from(&data[64..]).unwrap());
ww.and_then(|w| {
xx.and_then(|x| yy.and_then(|y| CtOption::new(Self { w, x, y }, Choice::from(1u8))))
})
}
pub fn sign<B: AsRef<[u8]>>(&self, id: B) -> Option<Token> {
Token::new(self, id)
}
}