snarkvm_console_account/
lib.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18#![warn(clippy::cast_possible_truncation)]
19#![cfg_attr(test, allow(clippy::assertions_on_result_states))]
20
21pub use snarkvm_console_types::{Address, Field, Group, Scalar, environment::prelude::*};
22
23mod address;
24
25#[cfg(feature = "compute_key")]
26pub mod compute_key;
27#[cfg(feature = "compute_key")]
28pub use compute_key::*;
29
30#[cfg(feature = "graph_key")]
31pub mod graph_key;
32#[cfg(feature = "graph_key")]
33pub use graph_key::*;
34
35#[cfg(feature = "private_key")]
36pub mod private_key;
37#[cfg(feature = "private_key")]
38pub use private_key::*;
39
40#[cfg(feature = "signature")]
41pub mod signature;
42#[cfg(feature = "signature")]
43pub use signature::*;
44
45#[cfg(feature = "view_key")]
46pub mod view_key;
47#[cfg(feature = "view_key")]
48pub use view_key::*;
49
50#[cfg(test)]
51mod tests {
52    use crate::{Address, ComputeKey, PrivateKey, Signature, ViewKey};
53    use snarkvm_console_network::{MainnetV0, prelude::*};
54
55    type CurrentNetwork = MainnetV0;
56
57    const ALEO_PRIVATE_KEY: &str = "APrivateKey1zkp8cC4jgHEBnbtu3xxs1Ndja2EMizcvTRDq5Nikdkukg1p";
58    const ALEO_VIEW_KEY: &str = "AViewKey1n1n3ZbnVEtXVe3La2xWkUvY3EY7XaCG6RZJJ3tbvrrrD";
59    const ALEO_ADDRESS: &str = "aleo1wvgwnqvy46qq0zemj0k6sfp3zv0mp77rw97khvwuhac05yuwscxqmfyhwf";
60
61    const ITERATIONS: usize = 1_000;
62
63    #[test]
64    fn test_account_derivation() {
65        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
66        let view_key = ViewKey::<CurrentNetwork>::try_from(&private_key).unwrap();
67        let address = Address::<CurrentNetwork>::try_from(&private_key).unwrap();
68
69        assert_eq!(ALEO_PRIVATE_KEY, private_key.to_string());
70        assert_eq!(ALEO_VIEW_KEY, view_key.to_string());
71        assert_eq!(ALEO_ADDRESS, address.to_string());
72    }
73
74    #[test]
75    fn test_private_key_from_str() {
76        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
77        assert_eq!(ALEO_PRIVATE_KEY, private_key.to_string());
78    }
79
80    #[test]
81    fn test_private_key_from_invalid_str() {
82        assert!(PrivateKey::<CurrentNetwork>::from_str(ALEO_VIEW_KEY).is_err());
83        assert!(PrivateKey::<CurrentNetwork>::from_str(ALEO_ADDRESS).is_err());
84        assert!(PrivateKey::<CurrentNetwork>::from_str("APrivateKey1abcdefghijklmnopqrstuvwxyz").is_err());
85        assert!(PrivateKey::<CurrentNetwork>::from_str("APrivateKey1").is_err());
86        assert!(PrivateKey::<CurrentNetwork>::from_str("").is_err());
87    }
88
89    #[test]
90    fn test_private_key_try_into_view_key() {
91        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
92        let view_key: ViewKey<_> = private_key.try_into().unwrap();
93        assert_eq!(ALEO_VIEW_KEY, view_key.to_string());
94    }
95
96    #[test]
97    fn test_view_key_from_str() {
98        let view_key = ViewKey::<CurrentNetwork>::from_str(ALEO_VIEW_KEY).unwrap();
99        assert_eq!(ALEO_VIEW_KEY, view_key.to_string());
100    }
101
102    #[test]
103    fn test_view_key_from_invalid_str() {
104        assert!(ViewKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).is_err());
105        assert!(ViewKey::<CurrentNetwork>::from_str(ALEO_ADDRESS).is_err());
106        assert!(ViewKey::<CurrentNetwork>::from_str("AViewKey1abcdefghijklmnopqrstuvwxyz").is_err());
107        assert!(ViewKey::<CurrentNetwork>::from_str("AViewKey1").is_err());
108        assert!(ViewKey::<CurrentNetwork>::from_str("").is_err());
109    }
110
111    #[test]
112    fn test_private_key_try_into_address() {
113        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
114        let address: Address<_> = private_key.try_into().unwrap();
115        assert_eq!(ALEO_ADDRESS, address.to_string());
116    }
117
118    #[test]
119    fn test_compute_key_try_into_address() {
120        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
121        let compute_key: ComputeKey<_> = private_key.try_into().unwrap();
122        let address: Address<_> = compute_key.try_into().unwrap();
123        assert_eq!(ALEO_ADDRESS, address.to_string());
124    }
125
126    #[test]
127    fn test_view_key_try_into_address() {
128        let view_key = ViewKey::<CurrentNetwork>::from_str(ALEO_VIEW_KEY).unwrap();
129        let address: Address<_> = view_key.try_into().unwrap();
130        assert_eq!(ALEO_ADDRESS, address.to_string());
131    }
132
133    #[test]
134    fn test_address_from_str() {
135        let address = Address::<CurrentNetwork>::from_str(ALEO_ADDRESS).unwrap();
136        assert_eq!(ALEO_ADDRESS, address.to_string());
137    }
138
139    #[test]
140    fn test_address_from_invalid_str() {
141        assert!(Address::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).is_err());
142        assert!(Address::<CurrentNetwork>::from_str(ALEO_VIEW_KEY).is_err());
143        assert!(Address::<CurrentNetwork>::from_str("aleo1abcdefghijklmnopqrstuvwxyz").is_err());
144        assert!(Address::<CurrentNetwork>::from_str("aleo1").is_err());
145        assert!(Address::<CurrentNetwork>::from_str("").is_err());
146    }
147
148    #[test]
149    fn test_sign_bits() {
150        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
151        let address = Address::<CurrentNetwork>::try_from(&private_key).unwrap();
152
153        let mut rng = TestRng::default();
154
155        for i in 0..ITERATIONS {
156            let message: Vec<bool> = (0..(32 * i)).map(|_| bool::rand(&mut rng)).collect();
157            let signature = private_key.sign_bits(&message, &mut rng).unwrap();
158            let verification = signature.verify_bits(&address, &message);
159            assert!(verification);
160        }
161    }
162
163    #[test]
164    fn test_invalid_sign_bits() {
165        let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
166        let address = Address::<CurrentNetwork>::try_from(&private_key).unwrap();
167
168        let mut rng = TestRng::default();
169
170        for i in 0..ITERATIONS {
171            let message = "Hi, I'm an Aleo account signature!".as_bytes().to_bits_le();
172            let incorrect_message: Vec<bool> = (0..(32 * i)).map(|_| bool::rand(&mut rng)).collect();
173
174            let signature = private_key.sign_bits(&message, &mut rng).unwrap();
175            let verification = signature.verify_bits(&address, &incorrect_message);
176            assert!(!verification);
177        }
178    }
179
180    #[test]
181    fn test_aleo_signature_bech32() {
182        let mut rng = TestRng::default();
183
184        for i in 0..25 {
185            // Sample an Aleo account.
186            let private_key = PrivateKey::<CurrentNetwork>::new(&mut rng).unwrap();
187
188            // Craft the Aleo signature.
189            let message: Vec<bool> = (0..(32 * i)).map(|_| bool::rand(&mut rng)).collect();
190            let expected_signature = private_key.sign_bits(&message, &mut rng).unwrap();
191
192            let candidate_string = &expected_signature.to_string();
193            assert_eq!(216, candidate_string.len(), "Update me if serialization has changed");
194            assert_eq!("sign1", &candidate_string[0..5], "Update me if the prefix has changed");
195        }
196    }
197
198    #[test]
199    fn test_aleo_signature_serde_json() {
200        let mut rng = TestRng::default();
201
202        for i in 0..25 {
203            // Sample an Aleo account.
204            let private_key = PrivateKey::<CurrentNetwork>::new(&mut rng).unwrap();
205
206            // Craft the Aleo signature.
207            let message: Vec<bool> = (0..(32 * i)).map(|_| bool::rand(&mut rng)).collect();
208            let expected_signature = private_key.sign_bits(&message, &mut rng).unwrap();
209
210            // Serialize
211            let expected_string = &expected_signature.to_string();
212            let candidate_string = serde_json::to_string(&expected_signature).unwrap();
213            assert_eq!(expected_string, serde_json::Value::from_str(&candidate_string).unwrap().as_str().unwrap());
214
215            // Deserialize
216            assert_eq!(expected_signature, serde_json::from_str(&candidate_string).unwrap());
217            assert_eq!(expected_signature, Signature::<CurrentNetwork>::from_str(expected_string).unwrap());
218        }
219    }
220
221    #[test]
222    fn test_aleo_signature_bincode() {
223        let mut rng = TestRng::default();
224
225        for i in 0..25 {
226            // Sample an Aleo account.
227            let private_key = PrivateKey::<CurrentNetwork>::new(&mut rng).unwrap();
228
229            // Craft the Aleo signature.
230            let message: Vec<bool> = (0..(32 * i)).map(|_| bool::rand(&mut rng)).collect();
231            let expected_signature = private_key.sign_bits(&message, &mut rng).unwrap();
232
233            // Serialize
234            let expected_bytes = expected_signature.to_bytes_le().unwrap();
235            let candidate_bytes = bincode::serialize(&expected_signature).unwrap();
236            assert_eq!(128, expected_bytes.len(), "Update me if serialization has changed");
237            assert_eq!(&expected_bytes[..], &candidate_bytes[8..]);
238
239            // Deserialize
240            assert_eq!(expected_signature, bincode::deserialize(&candidate_bytes[..]).unwrap());
241            assert_eq!(expected_signature, Signature::<CurrentNetwork>::read_le(&expected_bytes[..]).unwrap());
242        }
243    }
244}