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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use super::*;

/// Multicipher public key
///
/// A public key (also called shared key or pk in some literature) is that part
/// of an asymmetric keypair which can be used to verify the authenticity of the
/// sender of a message or to encrypt a message that can only be decrypted by a
/// single recipient. In both cases this other party owns the {@link PrivateKey}
/// part of the keypair and never shares it with anyone else.
#[wasm_bindgen(js_name = PublicKey)]
#[derive(Clone, Debug)]
pub struct JsMPublicKey {
    inner: MPublicKey,
}

#[wasm_bindgen(js_class = PublicKey)]
impl JsMPublicKey {
    /// Parses a string into a {@link PublicKey}.
    #[wasm_bindgen(constructor)]
    pub fn new(pub_key_str: &str) -> Result<JsMPublicKey, JsValue> {
        let inner: MPublicKey = pub_key_str.parse().map_err_to_js()?;
        Ok(Self { inner })
    }

    /// Converts a {@link SecpPublicKey} into a multicipher {@link PublicKey}.
    #[wasm_bindgen(js_name = fromSecp)]
    pub fn from_secp(pk: &JsSecpPublicKey) -> Self {
        let inner = MPublicKey::from(pk.inner().clone());
        Self { inner }
    }

    /// All multicipher public keys start with this prefix
    #[wasm_bindgen]
    pub fn prefix() -> String {
        MPublicKey::PREFIX.to_string()
    }

    /// Calculates the key id (also called fingerprint or address in some
    /// literature) of the public key.
    #[wasm_bindgen(js_name = keyId)]
    pub fn key_id(&self) -> JsMKeyId {
        JsMKeyId::from(self.inner.key_id())
    }

    /// Validates if `key_id` belongs to this public key
    ///
    /// We do not yet have multiple versions of key ids for the same multicipher
    /// public key, so for now this comparison is trivial. But when we introduce
    /// newer versions, we need to take the version of the `key_id` argument
    /// into account and calculate that possibly older version from `self`.
    #[wasm_bindgen(js_name = validateId)]
    pub fn validate_id(&self, key_id: &JsMKeyId) -> bool {
        self.inner.validate_id(key_id.inner())
    }

    /// This method can be used to verify if a given signature for a message was
    /// made using the private key that belongs to this public key.
    ///
    /// @see PrivateKey.sign
    #[wasm_bindgen(js_name = validateEcdsa)]
    pub fn validate_ecdsa(&self, data: &[u8], signature: &JsMSignature) -> bool {
        self.inner.verify(data, signature.inner())
    }

    /// Converts a {@link PublicKey} into a string.
    // Note that Clippy complains if you call these methods to_string. But implementing Display is not enough to get a toString in JS.
    #[wasm_bindgen(js_name=toString)]
    pub fn stringify(&self) -> String {
        self.inner.to_string()
    }
}

impl From<MPublicKey> for JsMPublicKey {
    fn from(inner: MPublicKey) -> Self {
        Self { inner }
    }
}

impl Wraps<MPublicKey> for JsMPublicKey {
    fn inner(&self) -> &MPublicKey {
        &self.inner
    }
}

/// Secp256k1 public key
#[wasm_bindgen(js_name = SecpPublicKey)]
#[derive(Clone, Debug)]
pub struct JsSecpPublicKey {
    inner: SecpPublicKey,
}

#[wasm_bindgen(js_class = SecpPublicKey)]
impl JsSecpPublicKey {
    /// Parses a string into a {@link SecpPublicKey}.
    #[wasm_bindgen(constructor)]
    pub fn new(key: &str) -> Result<JsSecpPublicKey, JsValue> {
        let inner: SecpPublicKey = key.parse().map_err_to_js()?;
        Ok(Self { inner })
    }

    /// Calculates the key id (also called fingerprint or address in some
    /// literature) of the public key.
    #[wasm_bindgen(js_name = keyId)]
    pub fn key_id(&self) -> JsSecpKeyId {
        JsSecpKeyId::from(self.inner.key_id())
    }

    /// Calculates the key id of the public key the non-standard way ark.io and
    /// therefore Hydra uses.
    ///
    /// Regular bitcoin-based chains use the ripemd160 hash of the sha2-256 hash
    /// of the public key, but ARK only uses ripemd160.
    #[wasm_bindgen(js_name = arkKeyId)]
    pub fn ark_key_id(&self) -> JsSecpKeyId {
        JsSecpKeyId::from(self.inner.ark_key_id())
    }

    /// Validates if `key_id` belongs to this public key
    #[wasm_bindgen(js_name = validateId)]
    pub fn validate_id(&self, key_id: &JsSecpKeyId) -> bool {
        self.inner.validate_id(key_id.inner())
    }

    /// Validates if `key_id` belongs to this public key if it was generated
    /// the ark.io way.
    #[wasm_bindgen(js_name = validateArkId)]
    pub fn validate_ark_id(&self, key_id: &JsSecpKeyId) -> bool {
        self.inner.validate_ark_id(key_id.inner())
    }

    /// This method can be used to verify if a given signature for a message was
    /// made using the private key that belongs to this public key.
    #[wasm_bindgen(js_name = validateEcdsa)]
    pub fn validate_ecdsa(&self, data: &[u8], signature: &JsSecpSignature) -> bool {
        self.inner.verify(data, signature.inner())
    }

    /// Converts a {@link SecpPublicKey} into a string.
    // Note that Clippy complains if you call these methods to_string. But implementing Display is not enough to get a toString in JS.
    #[wasm_bindgen(js_name=toString)]
    pub fn stringify(&self) -> String {
        self.inner.to_string()
    }
}

impl From<SecpPublicKey> for JsSecpPublicKey {
    fn from(inner: SecpPublicKey) -> Self {
        Self { inner }
    }
}

impl Wraps<SecpPublicKey> for JsSecpPublicKey {
    fn inner(&self) -> &SecpPublicKey {
        &self.inner
    }
}