Skip to content
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,7 @@ workflows:
or pipeline.git.branch == "testnet"
or pipeline.git.branch == "mainnet"
or pipeline.git.branch == "ensure_finalize_scopes_match"
or pipeline.git.branch == "feat/sign_v2"
jobs:
- check-unused-dependencies # This can be cleaned up before releases
- check-cargo-semver-checks # This can be cleaned up before releases
Expand Down
4 changes: 2 additions & 2 deletions circuit/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ pub(crate) mod helpers {

// Generate a signature.
let message: Vec<_> = (0..num_fields).map(|_| Uniform::rand(rng)).collect();
let signature = console::Signature::sign(&private_key, &message, rng).unwrap();
assert!(signature.verify(&address, &message));
let signature = console::Signature::sign_v2(&private_key, &message, rng).unwrap();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this arithmetization equivalent / backwards compatible?

assert!(signature.verify_v2(&address, &message));
signature
}
}
2 changes: 1 addition & 1 deletion circuit/account/src/signature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ mod tests {
for i in 0..ITERATIONS {
// Generate a signature.
let message: Vec<_> = (0..i).map(|_| Uniform::rand(rng)).collect();
let signature = console::Signature::sign(&private_key, &message, rng)?;
let signature = console::Signature::sign_v2(&private_key, &message, rng)?;

Circuit::scope(format!("New {mode}"), || {
let candidate = Signature::<Circuit>::new(mode, signature);
Expand Down
43 changes: 43 additions & 0 deletions console/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ mod tests {
}

#[test]
#[allow(deprecated)]
fn test_sign_bits() {
let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
let address = Address::<CurrentNetwork>::try_from(&private_key).unwrap();
Expand All @@ -157,10 +158,15 @@ mod tests {
let signature = private_key.sign_bits(&message, &mut rng).unwrap();
let verification = signature.verify_bits(&address, &message);
assert!(verification);
let signature_v2 = private_key.sign_bits_v2(&message, &mut rng).unwrap();
let verification_v2 = signature_v2.verify_bits_v2(&address, &message);
assert!(verification_v2);
}

Comment on lines 164 to +165

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

}

#[test]
#[allow(deprecated)]
fn test_invalid_sign_bits() {
let private_key = PrivateKey::<CurrentNetwork>::from_str(ALEO_PRIVATE_KEY).unwrap();
let address = Address::<CurrentNetwork>::try_from(&private_key).unwrap();
Expand All @@ -174,10 +180,14 @@ mod tests {
let signature = private_key.sign_bits(&message, &mut rng).unwrap();
let verification = signature.verify_bits(&address, &incorrect_message);
assert!(!verification);
let signature_v2 = private_key.sign_bits_v2(&message, &mut rng).unwrap();
let verification_v2 = signature_v2.verify_bits_v2(&address, &incorrect_message);
assert!(!verification_v2);
}
}

#[test]
#[allow(deprecated)]
fn test_aleo_signature_bech32() {
let mut rng = TestRng::default();

Expand All @@ -192,10 +202,17 @@ mod tests {
let candidate_string = &expected_signature.to_string();
assert_eq!(216, candidate_string.len(), "Update me if serialization has changed");
assert_eq!("sign1", &candidate_string[0..5], "Update me if the prefix has changed");

let expected_signature_v2 = private_key.sign_bits_v2(&message, &mut rng).unwrap();

let candidate_string = &expected_signature_v2.to_string();
assert_eq!(216, candidate_string.len(), "Update me if serialization has changed");
assert_eq!("sign1", &candidate_string[0..5], "Update me if the prefix has changed");
}
}

#[test]
#[allow(deprecated)]
fn test_aleo_signature_serde_json() {
let mut rng = TestRng::default();

Expand All @@ -215,10 +232,23 @@ mod tests {
// Deserialize
assert_eq!(expected_signature, serde_json::from_str(&candidate_string).unwrap());
assert_eq!(expected_signature, Signature::<CurrentNetwork>::from_str(expected_string).unwrap());

// Craft the Aleo signature with the v2 method.
let expected_signature_v2 = private_key.sign_bits_v2(&message, &mut rng).unwrap();

// Serialize
let expected_string = &expected_signature_v2.to_string();
let candidate_string = serde_json::to_string(&expected_signature).unwrap();
assert_eq!(expected_string, serde_json::Value::from_str(&candidate_string).unwrap().as_str().unwrap());

// Deserialize
assert_eq!(expected_signature_v2, serde_json::from_str(&candidate_string).unwrap());
assert_eq!(expected_signature, Signature::<CurrentNetwork>::from_str(expected_string).unwrap());
Comment on lines +241 to +246

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let candidate_string = serde_json::to_string(&expected_signature).unwrap();
assert_eq!(expected_string, serde_json::Value::from_str(&candidate_string).unwrap().as_str().unwrap());
// Deserialize
assert_eq!(expected_signature_v2, serde_json::from_str(&candidate_string).unwrap());
assert_eq!(expected_signature, Signature::<CurrentNetwork>::from_str(expected_string).unwrap());
let candidate_string = serde_json::to_string(&expected_signature_v2).unwrap();
assert_eq!(expected_string, serde_json::Value::from_str(&candidate_string).unwrap().as_str().unwrap());
// Deserialize
assert_eq!(expected_signature_v2, serde_json::from_str(&candidate_string).unwrap());
assert_eq!(expected_signature_v2, Signature::<CurrentNetwork>::from_str(expected_string).unwrap());

}
}

#[test]
#[allow(deprecated)]
fn test_aleo_signature_bincode() {
let mut rng = TestRng::default();

Expand All @@ -239,6 +269,19 @@ mod tests {
// Deserialize
assert_eq!(expected_signature, bincode::deserialize(&candidate_bytes[..]).unwrap());
assert_eq!(expected_signature, Signature::<CurrentNetwork>::read_le(&expected_bytes[..]).unwrap());

// Craft the Aleo signature with the v2 method.
let expected_signature_v2 = private_key.sign_bits_v2(&message, &mut rng).unwrap();

// Serialize
let expected_bytes = expected_signature_v2.to_bytes_le().unwrap();
let candidate_bytes = bincode::serialize(&expected_signature_v2).unwrap();
assert_eq!(128, expected_bytes.len(), "Update me if serialization has changed");
assert_eq!(&expected_bytes[..], &candidate_bytes[8..]);

// Deserialize
assert_eq!(expected_signature_v2, bincode::deserialize(&candidate_bytes[..]).unwrap());
assert_eq!(expected_signature_v2, Signature::<CurrentNetwork>::read_le(&expected_bytes[..]).unwrap());
}
}
}
36 changes: 36 additions & 0 deletions console/account/src/private_key/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,52 @@ use crate::Signature;

impl<N: Network> PrivateKey<N> {
/// Returns a signature for the given message (as field elements) using the private key.
#[deprecated(note="Please migrate to `sign_v2`")]
pub fn sign<R: Rng + CryptoRng>(&self, message: &[Field<N>], rng: &mut R) -> Result<Signature<N>> {
#[allow(deprecated)]
Signature::sign(self, message, rng)
}

/// Returns a signature for the given message (as bytes) using the private key.
#[deprecated(note="Please migrate to `sign_bytes_v2`")]
pub fn sign_bytes<R: Rng + CryptoRng>(&self, message: &[u8], rng: &mut R) -> Result<Signature<N>> {
#[allow(deprecated)]
Signature::sign_bytes(self, message, rng)
}

/// Returns a signature for the given message (as bits) using the private key.
#[deprecated(note="Please migrate to `sign_bits_v2`")]
pub fn sign_bits<R: Rng + CryptoRng>(&self, message: &[bool], rng: &mut R) -> Result<Signature<N>> {
#[allow(deprecated)]
Signature::sign_bits(self, message, rng)
}

/// Returns a signature for the given message (as field elements) using the private key.
pub fn sign_v2<R: Rng + CryptoRng>(&self, message: &[Field<N>], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_v2(self, message, rng)
}

/// Returns a signature for the given message (as bytes) using the private key.
pub fn sign_bytes_v2<R: Rng + CryptoRng>(&self, message: &[u8], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_bytes_v2(self, message, rng)
}

/// Returns a signature for the given message (as bytes) using the private key.
/// Message length is not encoded and must be checked by the caller if relevant.
pub fn sign_bytes_raw_v2<R: Rng + CryptoRng>(&self, message: &[u8], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_bytes_raw_v2(self, message, rng)
}

/// Returns a signature for the given message (as bits) using the private key.
pub fn sign_bits_v2<R: Rng + CryptoRng>(&self, message: &[bool], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_bits_v2(self, message, rng)
}

/// Returns a signature for the given message (as bits) using the private key.
/// Message length is not encoded and must be checked by the caller if relevant.
pub fn sign_bits_raw_v2<R: Rng + CryptoRng>(&self, message: &[bool], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_bits_raw_v2(self, message, rng)
}
}

#[cfg(test)]
Expand All @@ -44,6 +77,7 @@ mod tests {
const ITERATIONS: u64 = 100;

#[test]
#[allow(deprecated)]
fn test_sign_and_verify() -> Result<()> {
let rng = &mut TestRng::default();

Expand All @@ -67,6 +101,7 @@ mod tests {
}

#[test]
#[allow(deprecated)]
fn test_sign_and_verify_bytes() -> Result<()> {
let rng = &mut TestRng::default();

Expand All @@ -90,6 +125,7 @@ mod tests {
}

#[test]
#[allow(deprecated)]
fn test_sign_and_verify_bits() -> Result<()> {
let rng = &mut TestRng::default();

Expand Down
3 changes: 3 additions & 0 deletions console/account/src/signature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ use crate::address::Address;
use snarkvm_console_network::prelude::*;
use snarkvm_console_types::{Boolean, Field, Scalar};

// Domain separator used in sign_v2 and related methods.
static SIGNATURE_V2_PREFIX: &str = "ALEO_SIGNATURE_V2";

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Signature<N: Network> {
/// The verifier challenge to check against.
Expand Down
2 changes: 1 addition & 1 deletion console/account/src/signature/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use super::*;
static SIGNATURE_PREFIX: &str = "sign";

impl<N: Network> Parser for Signature<N> {
/// Parses a string into an signature.
/// Parses a string into a signature.
#[inline]
fn parse(string: &str) -> ParserResult<Self> {
// Prepare a parser for the Aleo signature.
Expand Down
Loading