#![deny(
unused_import_braces,
unused_imports,
unused_comparisons,
unused_must_use,
unused_variables,
non_shorthand_field_patterns,
unreachable_code,
unused_parens
)]
#![cfg_attr(not(feature = "std"), no_std)]
pub use libsecp256k1_core::*;
use arrayref::{array_mut_ref, array_ref};
use core::convert::TryFrom;
use digest::{generic_array::GenericArray, Digest};
use rand::Rng;
#[cfg(feature = "std")]
use core::fmt;
#[cfg(feature = "hmac")]
use hmac_drbg::HmacDRBG;
#[cfg(feature = "std")]
use serde::{de, ser::Serializer, Deserialize, Serialize};
#[cfg(feature = "hmac")]
use sha2::Sha256;
#[cfg(feature = "hmac")]
use typenum::U32;
use crate::{
curve::{Affine, ECMultContext, ECMultGenContext, Field, Jacobian, Scalar},
util::{Decoder, SignatureArray},
};
#[cfg(feature = "lazy-static-context")]
lazy_static::lazy_static! {
pub static ref ECMULT_CONTEXT: Box<ECMultContext> = ECMultContext::new_boxed();
pub static ref ECMULT_GEN_CONTEXT: Box<ECMultGenContext> = ECMultGenContext::new_boxed();
}
#[cfg(all(feature = "static-context", not(feature = "lazy-static-context")))]
pub static ECMULT_CONTEXT: ECMultContext =
unsafe { ECMultContext::new_from_raw(include!(concat!(env!("OUT_DIR"), "/const.rs"))) };
#[cfg(all(feature = "static-context", not(feature = "lazy-static-context")))]
pub static ECMULT_GEN_CONTEXT: ECMultGenContext =
unsafe { ECMultGenContext::new_from_raw(include!(concat!(env!("OUT_DIR"), "/const_gen.rs"))) };
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct PublicKey(Affine);
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct SecretKey(Scalar);
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Signature {
pub r: Scalar,
pub s: Scalar,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct RecoveryId(u8);
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Message(pub Scalar);
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SharedSecret<D: Digest>(GenericArray<u8, D::OutputSize>);
impl<D> Copy for SharedSecret<D>
where
D: Copy + Digest,
GenericArray<u8, D::OutputSize>: Copy,
{
}
pub enum PublicKeyFormat {
Compressed,
Full,
Raw,
}
impl PublicKey {
pub fn from_secret_key_with_context(
seckey: &SecretKey,
context: &ECMultGenContext,
) -> PublicKey {
let mut pj = Jacobian::default();
context.ecmult_gen(&mut pj, &seckey.0);
let mut p = Affine::default();
p.set_gej(&pj);
PublicKey(p)
}
#[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
pub fn from_secret_key(seckey: &SecretKey) -> PublicKey {
Self::from_secret_key_with_context(seckey, &ECMULT_GEN_CONTEXT)
}
pub fn parse_slice(p: &[u8], format: Option<PublicKeyFormat>) -> Result<PublicKey, Error> {
let format = match (p.len(), format) {
(util::FULL_PUBLIC_KEY_SIZE, None)
| (util::FULL_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Full)) => PublicKeyFormat::Full,
(util::COMPRESSED_PUBLIC_KEY_SIZE, None)
| (util::COMPRESSED_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Compressed)) => {
PublicKeyFormat::Compressed
}
(util::RAW_PUBLIC_KEY_SIZE, None)
| (util::RAW_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Raw)) => PublicKeyFormat::Raw,
_ => return Err(Error::InvalidInputLength),
};
match format {
PublicKeyFormat::Full => {
let mut a = [0; util::FULL_PUBLIC_KEY_SIZE];
a.copy_from_slice(p);
Self::parse(&a)
}
PublicKeyFormat::Raw => {
use util::TAG_PUBKEY_FULL;
let mut a = [0; util::FULL_PUBLIC_KEY_SIZE];
a[0] = TAG_PUBKEY_FULL;
a[1..].copy_from_slice(p);
Self::parse(&a)
}
PublicKeyFormat::Compressed => {
let mut a = [0; util::COMPRESSED_PUBLIC_KEY_SIZE];
a.copy_from_slice(p);
Self::parse_compressed(&a)
}
}
}
pub fn parse(p: &[u8; util::FULL_PUBLIC_KEY_SIZE]) -> Result<PublicKey, Error> {
use util::{TAG_PUBKEY_FULL, TAG_PUBKEY_HYBRID_EVEN, TAG_PUBKEY_HYBRID_ODD};
if !(p[0] == TAG_PUBKEY_FULL
|| p[0] == TAG_PUBKEY_HYBRID_EVEN
|| p[0] == TAG_PUBKEY_HYBRID_ODD)
{
return Err(Error::InvalidPublicKey);
}
let mut x = Field::default();
let mut y = Field::default();
if !x.set_b32(array_ref!(p, 1, 32)) {
return Err(Error::InvalidPublicKey);
}
if !y.set_b32(array_ref!(p, 33, 32)) {
return Err(Error::InvalidPublicKey);
}
let mut elem = Affine::default();
elem.set_xy(&x, &y);
if (p[0] == TAG_PUBKEY_HYBRID_EVEN || p[0] == TAG_PUBKEY_HYBRID_ODD)
&& (y.is_odd() != (p[0] == TAG_PUBKEY_HYBRID_ODD))
{
return Err(Error::InvalidPublicKey);
}
if elem.is_infinity() {
return Err(Error::InvalidPublicKey);
}
if elem.is_valid_var() {
Ok(PublicKey(elem))
} else {
Err(Error::InvalidPublicKey)
}
}
pub fn parse_compressed(
p: &[u8; util::COMPRESSED_PUBLIC_KEY_SIZE],
) -> Result<PublicKey, Error> {
use util::{TAG_PUBKEY_EVEN, TAG_PUBKEY_ODD};
if !(p[0] == TAG_PUBKEY_EVEN || p[0] == TAG_PUBKEY_ODD) {
return Err(Error::InvalidPublicKey);
}
let mut x = Field::default();
if !x.set_b32(array_ref!(p, 1, 32)) {
return Err(Error::InvalidPublicKey);
}
let mut elem = Affine::default();
elem.set_xo_var(&x, p[0] == TAG_PUBKEY_ODD);
if elem.is_infinity() {
return Err(Error::InvalidPublicKey);
}
if elem.is_valid_var() {
Ok(PublicKey(elem))
} else {
Err(Error::InvalidPublicKey)
}
}
pub fn serialize(&self) -> [u8; util::FULL_PUBLIC_KEY_SIZE] {
use util::TAG_PUBKEY_FULL;
debug_assert!(!self.0.is_infinity());
let mut ret = [0u8; 65];
let mut elem = self.0;
elem.x.normalize_var();
elem.y.normalize_var();
elem.x.fill_b32(array_mut_ref!(ret, 1, 32));
elem.y.fill_b32(array_mut_ref!(ret, 33, 32));
ret[0] = TAG_PUBKEY_FULL;
ret
}
pub fn serialize_compressed(&self) -> [u8; util::COMPRESSED_PUBLIC_KEY_SIZE] {
use util::{TAG_PUBKEY_EVEN, TAG_PUBKEY_ODD};
debug_assert!(!self.0.is_infinity());
let mut ret = [0u8; 33];
let mut elem = self.0;
elem.x.normalize_var();
elem.y.normalize_var();
elem.x.fill_b32(array_mut_ref!(ret, 1, 32));
ret[0] = if elem.y.is_odd() {
TAG_PUBKEY_ODD
} else {
TAG_PUBKEY_EVEN
};
ret
}
pub fn tweak_add_assign_with_context(
&mut self,
tweak: &SecretKey,
context: &ECMultContext,
) -> Result<(), Error> {
let mut r = Jacobian::default();
let a = Jacobian::from_ge(&self.0);
let one = Scalar::from_int(1);
context.ecmult(&mut r, &a, &one, &tweak.0);
if r.is_infinity() {
return Err(Error::TweakOutOfRange);
}
self.0.set_gej(&r);
Ok(())
}
#[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> {
self.tweak_add_assign_with_context(tweak, &ECMULT_CONTEXT)
}
pub fn tweak_mul_assign_with_context(
&mut self,
tweak: &SecretKey,
context: &ECMultContext,
) -> Result<(), Error> {
if tweak.0.is_zero() {
return Err(Error::TweakOutOfRange);
}
let mut r = Jacobian::default();
let zero = Scalar::from_int(0);
let pt = Jacobian::from_ge(&self.0);
context.ecmult(&mut r, &pt, &tweak.0, &zero);
self.0.set_gej(&r);
Ok(())
}
#[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> {
self.tweak_mul_assign_with_context(tweak, &ECMULT_CONTEXT)
}
pub fn combine(keys: &[PublicKey]) -> Result<Self, Error> {
let mut qj = Jacobian::default();
qj.set_infinity();
for key in keys {
qj = qj.add_ge(&key.0);
}
if qj.is_infinity() {
return Err(Error::InvalidPublicKey);
}
let q = Affine::from_gej(&qj);
Ok(PublicKey(q))
}
}
impl Into<Affine> for PublicKey {
fn into(self) -> Affine {
self.0
}
}
impl TryFrom<Affine> for PublicKey {
type Error = Error;
fn try_from(value: Affine) -> Result<Self, Self::Error> {
if value.is_infinity() || !value.is_valid_var() {
Err(Error::InvalidAffine)
} else {
Ok(PublicKey(value))
}
}
}
#[cfg(feature = "std")]
impl Serialize for PublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&base64::encode(&self.serialize()[..]))
} else {
serializer.serialize_bytes(&self.serialize())
}
}
}
#[cfg(feature = "std")]
struct PublicKeyStrVisitor;
#[cfg(feature = "std")]
impl<'de> de::Visitor<'de> for PublicKeyStrVisitor {
type Value = PublicKey;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.write_str("a bytestring of either 33 (compressed), 64 (raw), or 65 bytes in length")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let value: &[u8] = &base64::decode(value).map_err(|e| E::custom(e))?;
let key_format = match value.len() {
33 => PublicKeyFormat::Compressed,
64 => PublicKeyFormat::Raw,
65 => PublicKeyFormat::Full,
_ => return Err(E::custom(Error::InvalidInputLength)),
};
PublicKey::parse_slice(value, Some(key_format))
.map_err(|_e| E::custom(Error::InvalidPublicKey))
}
}
#[cfg(feature = "std")]
struct PublicKeyBytesVisitor;
#[cfg(feature = "std")]
impl<'de> de::Visitor<'de> for PublicKeyBytesVisitor {
type Value = PublicKey;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(
"a byte slice that is either 33 (compressed), 64 (raw), or 65 bytes in length",
)
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
PublicKey::parse_slice(value, None).map_err(|_e| E::custom(Error::InvalidPublicKey))
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for PublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_str(PublicKeyStrVisitor)
} else {
deserializer.deserialize_bytes(PublicKeyBytesVisitor)
}
}
}
impl SecretKey {
pub fn parse(p: &[u8; util::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
let mut elem = Scalar::default();
if !bool::from(elem.set_b32(p)) {
Self::try_from(elem)
} else {
Err(Error::InvalidSecretKey)
}
}
pub fn parse_slice(p: &[u8]) -> Result<SecretKey, Error> {
if p.len() != util::SECRET_KEY_SIZE {
return Err(Error::InvalidInputLength);
}
let mut a = [0; 32];
a.copy_from_slice(p);
Self::parse(&a)
}
pub fn random<R: Rng>(rng: &mut R) -> SecretKey {
loop {
let mut ret = [0u8; util::SECRET_KEY_SIZE];
rng.fill_bytes(&mut ret);
if let Ok(key) = Self::parse(&ret) {
return key;
}
}
}
pub fn serialize(&self) -> [u8; util::SECRET_KEY_SIZE] {
self.0.b32()
}
pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> {
let v = self.0 + tweak.0;
if v.is_zero() {
return Err(Error::TweakOutOfRange);
}
self.0 = v;
Ok(())
}
pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> {
if tweak.0.is_zero() {
return Err(Error::TweakOutOfRange);
}
self.0 *= &tweak.0;
Ok(())
}
pub fn inv(&self) -> Self {
SecretKey(self.0.inv())
}
}
impl Default for SecretKey {
fn default() -> SecretKey {
let mut elem = Scalar::default();
let overflowed = bool::from(elem.set_b32(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
]));
debug_assert!(!overflowed);
debug_assert!(!elem.is_zero());
SecretKey(elem)
}
}
impl Into<Scalar> for SecretKey {
fn into(self) -> Scalar {
self.0
}
}
impl TryFrom<Scalar> for SecretKey {
type Error = Error;
fn try_from(scalar: Scalar) -> Result<Self, Error> {
if scalar.is_zero() {
Err(Error::InvalidSecretKey)
} else {
Ok(Self(scalar))
}
}
}
impl core::fmt::LowerHex for SecretKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let scalar = self.0;
write!(f, "{:x}", scalar)
}
}
impl Signature {
pub fn parse_overflowing(p: &[u8; util::SIGNATURE_SIZE]) -> Signature {
let mut r = Scalar::default();
let mut s = Scalar::default();
let _ = r.set_b32(array_ref!(p, 0, 32));
let _ = s.set_b32(array_ref!(p, 32, 32));
Signature { r, s }
}
pub fn parse_standard(p: &[u8; util::SIGNATURE_SIZE]) -> Result<Signature, Error> {
let mut r = Scalar::default();
let mut s = Scalar::default();
let overflowed_r = r.set_b32(array_ref!(p, 0, 32));
let overflowed_s = s.set_b32(array_ref!(p, 32, 32));
if bool::from(overflowed_r | overflowed_s) {
return Err(Error::InvalidSignature);
}
Ok(Signature { r, s })
}
pub fn parse_overflowing_slice(p: &[u8]) -> Result<Signature, Error> {
if p.len() != util::SIGNATURE_SIZE {
return Err(Error::InvalidInputLength);
}
let mut a = [0; util::SIGNATURE_SIZE];
a.copy_from_slice(p);
Ok(Self::parse_overflowing(&a))
}
pub fn parse_standard_slice(p: &[u8]) -> Result<Signature, Error> {
if p.len() != util::SIGNATURE_SIZE {
return Err(Error::InvalidInputLength);
}
let mut a = [0; util::SIGNATURE_SIZE];
a.copy_from_slice(p);
Ok(Self::parse_standard(&a)?)
}
pub fn parse_der(p: &[u8]) -> Result<Signature, Error> {
let mut decoder = Decoder::new(p);
decoder.read_constructed_sequence()?;
let rlen = decoder.read_len()?;
if rlen != decoder.remaining_len() {
return Err(Error::InvalidSignature);
}
let r = decoder.read_integer()?;
let s = decoder.read_integer()?;
if decoder.remaining_len() != 0 {
return Err(Error::InvalidSignature);
}
Ok(Signature { r, s })
}
pub fn parse_der_lax(p: &[u8]) -> Result<Signature, Error> {
let mut decoder = Decoder::new(p);
decoder.read_constructed_sequence()?;
decoder.read_seq_len_lax()?;
let r = decoder.read_integer_lax()?;
let s = decoder.read_integer_lax()?;
Ok(Signature { r, s })
}
pub fn normalize_s(&mut self) {
if self.s.is_high() {
self.s = -self.s;
}
}
pub fn serialize(&self) -> [u8; util::SIGNATURE_SIZE] {
let mut ret = [0u8; 64];
self.r.fill_b32(array_mut_ref!(ret, 0, 32));
self.s.fill_b32(array_mut_ref!(ret, 32, 32));
ret
}
pub fn serialize_der(&self) -> SignatureArray {
fn fill_scalar_with_leading_zero(scalar: &Scalar) -> [u8; 33] {
let mut ret = [0u8; 33];
scalar.fill_b32(array_mut_ref!(ret, 1, 32));
ret
}
let r_full = fill_scalar_with_leading_zero(&self.r);
let s_full = fill_scalar_with_leading_zero(&self.s);
fn integer_slice(full: &[u8; 33]) -> &[u8] {
let mut len = 33;
while len > 1 && full[full.len() - len] == 0 && full[full.len() - len + 1] < 0x80 {
len -= 1;
}
&full[(full.len() - len)..]
}
let r = integer_slice(&r_full);
let s = integer_slice(&s_full);
let mut ret = SignatureArray::new(6 + r.len() + s.len());
{
let l = ret.as_mut();
l[0] = 0x30;
l[1] = 4 + r.len() as u8 + s.len() as u8;
l[2] = 0x02;
l[3] = r.len() as u8;
l[4..(4 + r.len())].copy_from_slice(r);
l[4 + r.len()] = 0x02;
l[5 + r.len()] = s.len() as u8;
l[(6 + r.len())..(6 + r.len() + s.len())].copy_from_slice(s);
}
ret
}
}
impl Message {
pub fn parse(p: &[u8; util::MESSAGE_SIZE]) -> Message {
let mut m = Scalar::default();
let _ = m.set_b32(p);
Message(m)
}
pub fn parse_slice(p: &[u8]) -> Result<Message, Error> {
if p.len() != util::MESSAGE_SIZE {
return Err(Error::InvalidInputLength);
}
let mut a = [0; util::MESSAGE_SIZE];
a.copy_from_slice(p);
Ok(Self::parse(&a))
}
pub fn serialize(&self) -> [u8; util::MESSAGE_SIZE] {
self.0.b32()
}
}
impl RecoveryId {
pub fn parse(p: u8) -> Result<RecoveryId, Error> {
if p < 4 {
Ok(RecoveryId(p))
} else {
Err(Error::InvalidRecoveryId)
}
}
pub fn parse_rpc(p: u8) -> Result<RecoveryId, Error> {
if p >= 27 && p < 27 + 4 {
RecoveryId::parse(p - 27)
} else {
Err(Error::InvalidRecoveryId)
}
}
pub fn serialize(&self) -> u8 {
self.0
}
}
impl Into<u8> for RecoveryId {
fn into(self) -> u8 {
self.0
}
}
impl Into<i32> for RecoveryId {
fn into(self) -> i32 {
self.0 as i32
}
}
impl<D: Digest + Default> SharedSecret<D> {
pub fn new_with_context(
pubkey: &PublicKey,
seckey: &SecretKey,
context: &ECMultContext,
) -> Result<SharedSecret<D>, Error> {
let inner = match context.ecdh_raw::<D>(&pubkey.0, &seckey.0) {
Some(val) => val,
None => return Err(Error::InvalidSecretKey),
};
Ok(SharedSecret(inner))
}
#[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
pub fn new(pubkey: &PublicKey, seckey: &SecretKey) -> Result<SharedSecret<D>, Error> {
Self::new_with_context(pubkey, seckey, &ECMULT_CONTEXT)
}
}
impl<D: Digest> AsRef<[u8]> for SharedSecret<D> {
fn as_ref(&self) -> &[u8] {
&self.0.as_ref()
}
}
pub fn verify_with_context(
message: &Message,
signature: &Signature,
pubkey: &PublicKey,
context: &ECMultContext,
) -> bool {
context.verify_raw(&signature.r, &signature.s, &pubkey.0, &message.0)
}
#[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
pub fn verify(message: &Message, signature: &Signature, pubkey: &PublicKey) -> bool {
verify_with_context(message, signature, pubkey, &ECMULT_CONTEXT)
}
pub fn recover_with_context(
message: &Message,
signature: &Signature,
recovery_id: &RecoveryId,
context: &ECMultContext,
) -> Result<PublicKey, Error> {
context
.recover_raw(&signature.r, &signature.s, recovery_id.0, &message.0)
.map(PublicKey)
}
#[cfg(any(feature = "static-context", feature = "lazy-static-context"))]
pub fn recover(
message: &Message,
signature: &Signature,
recovery_id: &RecoveryId,
) -> Result<PublicKey, Error> {
recover_with_context(message, signature, recovery_id, &ECMULT_CONTEXT)
}
#[cfg(feature = "hmac")]
pub fn sign_with_context(
message: &Message,
seckey: &SecretKey,
context: &ECMultGenContext,
) -> (Signature, RecoveryId) {
let seckey_b32 = seckey.0.b32();
let message_b32 = message.0.b32();
let mut drbg = HmacDRBG::<Sha256>::new(&seckey_b32, &message_b32, &[]);
let mut nonce = Scalar::default();
let mut overflow;
let result;
loop {
let generated = drbg.generate::<U32>(None);
overflow = bool::from(nonce.set_b32(array_ref!(generated, 0, 32)));
if !overflow && !nonce.is_zero() {
if let Ok(val) = context.sign_raw(&seckey.0, &message.0, &nonce) {
result = val;
break;
}
}
}
#[allow(unused_assignments)]
{
nonce = Scalar::default();
}
let (sigr, sigs, recid) = result;
(Signature { r: sigr, s: sigs }, RecoveryId(recid))
}
#[cfg(all(
feature = "hmac",
any(feature = "static-context", feature = "lazy-static-context")
))]
pub fn sign(message: &Message, seckey: &SecretKey) -> (Signature, RecoveryId) {
sign_with_context(message, seckey, &ECMULT_GEN_CONTEXT)
}
#[cfg(test)]
mod tests {
use crate::SecretKey;
use hex_literal::hex;
#[test]
fn secret_key_inverse_is_sane() {
let sk = SecretKey::parse(&[1; 32]).unwrap();
let inv = sk.inv();
let invinv = inv.inv();
assert_eq!(sk, invinv);
assert_eq!(
inv,
SecretKey::parse(&hex!(
"1536f1d756d1abf83aaf173bc5ee3fc487c93010f18624d80bd6d4038fadd59e"
))
.unwrap()
)
}
}