Skip to content

Commit

Permalink
Add signing/verifying Aleo values
Browse files Browse the repository at this point in the history
  • Loading branch information
Meshiest committed Apr 16, 2024
1 parent d9cc20b commit e0cc5c5
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 1 deletion.
12 changes: 12 additions & 0 deletions sdk/docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ Working with signatures
>>> restored = aleo.Signature.from_string(serialized)
>>> assert account.verify(restored, message)

Working with signatures using Aleo values
***********************

.. doctest::

>>> account = aleo.Account()
>>> message = '5field'
>>> signature = account.sign_value(message)
>>> serialized = str(signature)
>>> restored = aleo.Signature.from_string(serialized)
>>> assert account.verify_value(restored, message)


Calling a **transfer_public** function
**************************************
Expand Down
19 changes: 19 additions & 0 deletions sdk/python/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ def test_signature_verify(self):
self.assertFalse(signature.verify(address, bad_message))
self.assertEqual(signature, aleo.Signature.from_string(c_signature))

def test_signature_verify_value(self):
address = aleo.Address.from_string(
"aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4")
c_signature = "sign1m9jrzpea7c8gdd0q7fp7pwszy6ar4du5p03aj8798c7pvwur9qqfhakcuf0xqelct6u8qylr0tkqwt46kngtg7capdlj6qeqkqevyqnavkjwgtm3t90lvxdrjjl07td0k4w5sysm7w22lfhfkqgdk690pcu5an22wssu4q6d3754cljxugdnrnccneldp79m3j5drzxs0s4sx2u5zze"
signature = aleo.Signature.from_string(c_signature)
message = "5field"
bad_message = "5u8"
self.assertTrue(signature.verify_value(address, message))
self.assertFalse(signature.verify_value(address, bad_message))
self.assertEqual(signature, aleo.Signature.from_string(c_signature))

def test_account_sanity(self):
private_key = aleo.PrivateKey.from_string(
"APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6")
Expand All @@ -65,6 +76,14 @@ def test_account_sanity(self):
self.assertFalse(account.verify(signature, bad_message))
self.assertTrue(signature.verify(account.address(), message))

message_value = "5field"
bad_message_value = "5u8"
signature_value = account.sign_value(message_value)

self.assertTrue(account.verify_value(signature_value, message_value))
self.assertFalse(account.verify_value(signature_value, bad_message_value))
self.assertTrue(signature_value.verify_value(account.address(), message_value))

def test_encrypt_decrypt_sk(self):
private_key = aleo.PrivateKey.from_string(
"APrivateKey1zkpJYx2NZeJYB74JHpzvQGpKneTP75Dk8dao6paugZXtCz3")
Expand Down
10 changes: 10 additions & 0 deletions sdk/src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,21 @@ impl Account {
self.private_key.sign(message)
}

/// Returns a signature for the given message (as an aleo value)
fn sign_value(&self, value: &str) -> anyhow::Result<Signature> {
self.private_key.sign_value(value)
}

/// Verifies the signature of the given message.
fn verify(&self, signature: &Signature, message: &[u8]) -> bool {
signature.verify(&self.address, message)
}

/// Verifies the signature of the given value.
fn verify_value(&self, signature: &Signature, value: &str) -> bool {
signature.verify_value(&self.address, value)
}

/// Decrypts a record ciphertext with a view key
fn decrypt(&self, record_ciphertext: &RecordCiphertext) -> anyhow::Result<RecordPlaintext> {
record_ciphertext.decrypt(&self.view_key)
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/account/private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ impl PrivateKey {
Signature::sign(self, message)
}

/// Returns a signature for the given message (as a field) using the private key.
pub fn sign_value(&self, value: &str) -> anyhow::Result<Signature> {
Signature::sign_value(self, value)
}

/// Returns the signature secret key.
fn sk_sig(&self) -> Scalar {
self.0.sk_sig().into()
Expand Down
25 changes: 24 additions & 1 deletion sdk/src/account/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with the Aleo SDK library. If not, see <https://www.gnu.org/licenses/>.

use crate::{types::SignatureNative, Address, ComputeKey, PrivateKey, Scalar};
use crate::{
types::{SignatureNative, ValueNative},
Address, ComputeKey, PrivateKey, Scalar,
};
use snarkvm::console::program::ToFields;

use pyo3::prelude::*;
use rand::{rngs::StdRng, SeedableRng};
Expand Down Expand Up @@ -62,12 +66,31 @@ impl Signature {
.map(Self)
}

/// Returns a signature for the given message (as bytes) using the private key.
#[staticmethod]
pub fn sign_value(private_key: &PrivateKey, value: &str) -> anyhow::Result<Self> {
let fields = ValueNative::from_str(value)?.to_fields()?;
private_key
.deref()
.sign(&fields, &mut StdRng::from_entropy())
.map(Self)
}

/// Verifies (challenge == challenge') && (address == address') where:
/// challenge' := HashToScalar(G^response pk_sig^challenge, pk_sig, pr_sig, address, message)
pub fn verify(&self, address: &Address, message: &[u8]) -> bool {
self.0.verify_bytes(address, message)
}

/// Verifies (challenge == challenge') && (address == address') where:
/// challenge' := HashToScalar(G^response pk_sig^challenge, pk_sig, pr_sig, address, message)
pub fn verify_value(&self, address: &Address, value: &str) -> bool {
let Ok(fields) = ValueNative::from_str(value).and_then(|v| v.to_fields()) else {
return false;
};
self.0.verify(address, &fields)
}

/// Returns a string representation of the signature.
fn __str__(&self) -> String {
self.0.to_string()
Expand Down

0 comments on commit e0cc5c5

Please sign in to comment.