diff --git a/cl/Cargo.toml b/cl/Cargo.toml index 5bfa4b3..c42d620 100644 --- a/cl/Cargo.toml +++ b/cl/Cargo.toml @@ -16,6 +16,6 @@ rand_core = "0.6.0" rand_chacha = "0.3.1" lazy_static = "1.4.0" hex = "0.4.3" -k256 = {version = "0.13.3", features = ["serde", "hash2curve"]} - +curve25519-dalek = {version = "4.1", features = ["serde", "digest", "rand_core"]} +sha2 = "0.10" diff --git a/cl/src/balance.rs b/cl/src/balance.rs index 68d6e59..91f185a 100644 --- a/cl/src/balance.rs +++ b/cl/src/balance.rs @@ -1,33 +1,25 @@ +use curve25519_dalek::{ristretto::RistrettoPoint, traits::VartimeMultiscalarMul, Scalar}; use lazy_static::lazy_static; -use rand_core::RngCore; +use rand_core::CryptoRngCore; use serde::{Deserialize, Serialize}; -use k256::{ - elliptic_curve::{ - group::GroupEncoding, Field - }, - ProjectivePoint, Scalar, AffinePoint -}; -use k256::elliptic_curve::ops::LinearCombinationExt; - - lazy_static! { - // Precompute of `crate::crypto::hash_to_curve(b"NOMOS_CL_PEDERSON_COMMITMENT_BLINDING")` - static ref PEDERSON_COMMITMENT_BLINDING_POINT: ProjectivePoint = ProjectivePoint::from_bytes((&[3, 130, 21, 159, 218, 6, 221, 181, 55, 169, 198, 220, 102, 48, 164, 23, 206, 225, 58, 54, 247, 64, 180, 120, 247, 101, 88, 97, 2, 206, 144, 92, 9]).into()).unwrap(); + // Precompute of `` + static ref PEDERSON_COMMITMENT_BLINDING_POINT: RistrettoPoint = crate::crypto::hash_to_curve(b"NOMOS_CL_PEDERSON_COMMITMENT_BLINDING"); } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Balance(pub AffinePoint); +pub struct Balance(pub RistrettoPoint); #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct BalanceWitness { pub value: u64, - pub unit: AffinePoint, + pub unit: RistrettoPoint, pub blinding: Scalar, } impl Balance { - pub fn to_bytes(&self) -> [u8; 33] { - self.0.to_bytes().into() + pub fn to_bytes(&self) -> [u8; 32] { + self.0.compress().to_bytes().into() } } @@ -40,8 +32,8 @@ impl BalanceWitness { } } - pub fn random(value: u64, unit: impl Into, rng: impl RngCore) -> Self { - Self::new(value, unit, Scalar::random(rng)) + pub fn random(value: u64, unit: impl Into, mut rng: impl CryptoRngCore) -> Self { + Self::new(value, unit, Scalar::random(&mut rng)) } pub fn commit(&self) -> Balance { @@ -49,13 +41,17 @@ impl BalanceWitness { } } -pub fn unit_point(unit: &str) -> ProjectivePoint { +pub fn unit_point(unit: &str) -> RistrettoPoint { crate::crypto::hash_to_curve(unit.as_bytes()) } -pub fn balance(value: u64, unit: ProjectivePoint, blinding: Scalar) -> ProjectivePoint { +pub fn balance(value: u64, unit: RistrettoPoint, blinding: Scalar) -> RistrettoPoint { let value_scalar = Scalar::from(value); - ProjectivePoint::lincomb_ext(&[(unit, value_scalar), (*PEDERSON_COMMITMENT_BLINDING_POINT, blinding)]) + // can vartime leak the number of cycles through the stark proof? + RistrettoPoint::vartime_multiscalar_mul( + &[value_scalar, blinding], + &[unit, *PEDERSON_COMMITMENT_BLINDING_POINT], + ) } // mod serde_scalar { @@ -152,16 +148,19 @@ pub fn balance(value: u64, unit: ProjectivePoint, blinding: Scalar) -> Projectiv #[cfg(test)] mod test { + use super::*; use crate::test_util::seed_rng; use k256::elliptic_curve::group::prime::PrimeCurveAffine; - use super::*; #[test] fn test_pederson_blinding_point_pre_compute() { // use k256::elliptic_curve::group::GroupEncoding; // println!("{:?}", <[u8;33]>::from((*PEDERSON_COMMITMENT_BLINDING_POINT).to_bytes())); - - assert_eq!(*PEDERSON_COMMITMENT_BLINDING_POINT, crate::crypto::hash_to_curve(b"NOMOS_CL_PEDERSON_COMMITMENT_BLINDING")); + + assert_eq!( + *PEDERSON_COMMITMENT_BLINDING_POINT, + crate::crypto::hash_to_curve(b"NOMOS_CL_PEDERSON_COMMITMENT_BLINDING") + ); } #[test] @@ -185,7 +184,10 @@ mod test { let a = a_w.commit(); let b = b_w.commit(); assert_ne!(a, b); - assert_eq!(a.0.to_curve() - b.0.to_curve(), BalanceWitness::new(0, "NMO", r1 - r2).commit().0.to_curve()); + assert_eq!( + a.0.to_curve() - b.0.to_curve(), + BalanceWitness::new(0, "NMO", r1 - r2).commit().0.to_curve() + ); } #[test] @@ -207,7 +209,10 @@ mod test { let two = BalanceWitness::new(2, "NMO", 0u32.into()); // Values of same unit are homomorphic - assert_eq!(ten.commit().0.to_curve() - eight.commit().0.to_curve(), two.commit().0.to_curve()); + assert_eq!( + ten.commit().0.to_curve() - eight.commit().0.to_curve(), + two.commit().0.to_curve() + ); // Blinding factors are also homomorphic. assert_eq!( diff --git a/cl/src/bundle.rs b/cl/src/bundle.rs index d4d8b76..db999ee 100644 --- a/cl/src/bundle.rs +++ b/cl/src/bundle.rs @@ -2,7 +2,7 @@ use std::collections::BTreeSet; use serde::{Deserialize, Serialize}; -use k256::{Scalar, ProjectivePoint}; +use curve25519_dalek::{constants::RISTRETTO_BASEPOINT_POINT, ristretto::RistrettoPoint, Scalar}; use crate::{ error::Error, @@ -31,12 +31,13 @@ pub struct BundleProof { } impl Bundle { - pub fn balance(&self) -> ProjectivePoint { + pub fn balance(&self) -> RistrettoPoint { self.partials.iter().map(|ptx| ptx.balance()).sum() } pub fn is_balanced(&self, balance_blinding_witness: Scalar) -> bool { - self.balance() == crate::balance::balance(0, ProjectivePoint::GENERATOR, balance_blinding_witness) + self.balance() + == crate::balance::balance(0, RISTRETTO_BASEPOINT_POINT, balance_blinding_witness) } pub fn prove( @@ -65,7 +66,9 @@ impl Bundle { return Err(Error::ProofFailed); } - if self.balance() != crate::balance::balance(0, ProjectivePoint::GENERATOR, w.balance_blinding) { + if self.balance() + != crate::balance::balance(0, RISTRETTO_BASEPOINT_POINT, w.balance_blinding) + { return Err(Error::ProofFailed); } @@ -89,9 +92,8 @@ impl Bundle { #[cfg(test)] mod test { use crate::{ - input::InputWitness, note::NoteWitness, nullifier::NullifierSecret, output::OutputWitness, - partial_tx::PartialTxWitness, test_util::seed_rng, - crypto::hash_to_curve, + crypto::hash_to_curve, input::InputWitness, note::NoteWitness, nullifier::NullifierSecret, + output::OutputWitness, partial_tx::PartialTxWitness, test_util::seed_rng, }; use super::*; @@ -128,9 +130,19 @@ mod test { assert!(!bundle.is_balanced(bundle_witness.balance_blinding)); assert_eq!( bundle.balance(), - crate::balance::balance(4840, hash_to_curve(b"CRV"), crv_4840_out.note.balance.blinding) - - (crate::balance::balance(10, hash_to_curve(b"NMO"), nmo_10_in.note.balance.blinding) - + crate::balance::balance(23, hash_to_curve(b"ETH"), eth_23_in.note.balance.blinding)) + crate::balance::balance( + 4840, + hash_to_curve(b"CRV"), + crv_4840_out.note.balance.blinding + ) - (crate::balance::balance( + 10, + hash_to_curve(b"NMO"), + nmo_10_in.note.balance.blinding + ) + crate::balance::balance( + 23, + hash_to_curve(b"ETH"), + eth_23_in.note.balance.blinding + )) ); let crv_4840_in = @@ -163,7 +175,7 @@ mod test { assert_eq!( bundle.balance(), - crate::balance::balance(0, ProjectivePoint::GENERATOR, witness.balance_blinding) + crate::balance::balance(0, RistrettoPoint::GENERATOR, witness.balance_blinding) ); assert!(bundle.is_balanced(witness.balance_blinding)); diff --git a/cl/src/crypto.rs b/cl/src/crypto.rs index 8f40569..8641ff1 100644 --- a/cl/src/crypto.rs +++ b/cl/src/crypto.rs @@ -1,8 +1,6 @@ -use k256::{Secp256k1, ProjectivePoint, elliptic_curve::{ - hash2curve::{GroupDigest, ExpandMsgXmd}, -},sha2::Sha256 -}; +use blake2::Blake2b512; +use curve25519_dalek::ristretto::RistrettoPoint; -pub fn hash_to_curve(bytes: &[u8]) -> ProjectivePoint { - Secp256k1::hash_from_bytes::>(&[bytes], &[b"NOMOS_HASH_TO_CURVE"]).unwrap() +pub fn hash_to_curve(bytes: &[u8]) -> RistrettoPoint { + RistrettoPoint::hash_from_bytes::(bytes) } diff --git a/cl/src/input.rs b/cl/src/input.rs index fb21fe7..a8bde4c 100644 --- a/cl/src/input.rs +++ b/cl/src/input.rs @@ -105,11 +105,11 @@ impl Input { && death_constraint_is_satisfied } - pub fn to_bytes(&self) -> [u8; 97] { - let mut bytes = [0u8; 97]; + pub fn to_bytes(&self) -> [u8; 96] { + let mut bytes = [0u8; 96]; bytes[..32].copy_from_slice(self.note_comm.as_bytes()); bytes[32..64].copy_from_slice(self.nullifier.as_bytes()); - bytes[64..97].copy_from_slice(&self.balance.to_bytes()); + bytes[64..96].copy_from_slice(&self.balance.to_bytes()); bytes } } diff --git a/cl/src/merkle.rs b/cl/src/merkle.rs index 2aec034..327c0d1 100644 --- a/cl/src/merkle.rs +++ b/cl/src/merkle.rs @@ -1,5 +1,5 @@ -use blake2::{Blake2s256, Digest}; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; pub fn padded_leaves(elements: &[Vec]) -> [[u8; 32]; N] { let mut leaves = [[0u8; 32]; N]; @@ -13,14 +13,14 @@ pub fn padded_leaves(elements: &[Vec]) -> [[u8; 32]; N] { } pub fn leaf(data: &[u8]) -> [u8; 32] { - let mut hasher = Blake2s256::new(); + let mut hasher = Sha256::new(); hasher.update(b"NOMOS_MERKLE_LEAF"); hasher.update(data); hasher.finalize().into() } pub fn node(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { - let mut hasher = Blake2s256::new(); + let mut hasher = Sha256::new(); hasher.update(b"NOMOS_MERKLE_NODE"); hasher.update(a); hasher.update(b); diff --git a/cl/src/note.rs b/cl/src/note.rs index d9cd2bc..8dabaea 100644 --- a/cl/src/note.rs +++ b/cl/src/note.rs @@ -1,7 +1,6 @@ use blake2::{Blake2s256, Digest}; -use rand_core::RngCore; +use rand_core::CryptoRngCore; use serde::{Deserialize, Serialize}; -use k256::elliptic_curve::group::GroupEncoding; use crate::{ balance::{Balance, BalanceWitness}, @@ -27,7 +26,12 @@ pub struct NoteWitness { } impl NoteWitness { - pub fn new(value: u64, unit: impl Into, state: [u8; 32], rng: impl RngCore) -> Self { + pub fn new( + value: u64, + unit: impl Into, + state: [u8; 32], + rng: impl CryptoRngCore, + ) -> Self { Self { balance: BalanceWitness::random(value, unit, rng), death_constraint: vec![], @@ -41,7 +45,7 @@ impl NoteWitness { // COMMIT TO BALANCE hasher.update(self.balance.value.to_le_bytes()); - hasher.update(self.balance.unit.to_bytes()); + hasher.update(self.balance.unit.compress().to_bytes()); // Important! we don't commit to the balance blinding factor as that may make the notes linkable. // COMMIT TO STATE diff --git a/cl/src/output.rs b/cl/src/output.rs index 846f697..f25c609 100644 --- a/cl/src/output.rs +++ b/cl/src/output.rs @@ -61,10 +61,10 @@ impl Output { && self.balance == witness.note.balance() } - pub fn to_bytes(&self) -> [u8; 65] { - let mut bytes = [0u8; 65]; + pub fn to_bytes(&self) -> [u8; 64] { + let mut bytes = [0u8; 64]; bytes[..32].copy_from_slice(self.note_comm.as_bytes()); - bytes[32..65].copy_from_slice(&self.balance.to_bytes()); + bytes[32..64].copy_from_slice(&self.balance.to_bytes()); bytes } } diff --git a/cl/src/partial_tx.rs b/cl/src/partial_tx.rs index 95cf669..70fa58e 100644 --- a/cl/src/partial_tx.rs +++ b/cl/src/partial_tx.rs @@ -2,9 +2,8 @@ use std::collections::BTreeSet; use rand_core::RngCore; // use risc0_groth16::ProofJson; +use curve25519_dalek::ristretto::RistrettoPoint; use serde::{Deserialize, Serialize}; -use k256::ProjectivePoint; -use k256::elliptic_curve::group::prime::PrimeCurveAffine; use crate::error::Error; use crate::input::{Input, InputProof, InputWitness}; @@ -158,9 +157,9 @@ impl PartialTx { .all(|(o, p)| o.verify(p)) } - pub fn balance(&self) -> ProjectivePoint { - let in_sum: ProjectivePoint = self.inputs.iter().map(|i| i.balance.0.to_curve()).sum(); - let out_sum: ProjectivePoint = self.outputs.iter().map(|o| o.balance.0.to_curve()).sum(); + pub fn balance(&self) -> RistrettoPoint { + let in_sum: RistrettoPoint = self.inputs.iter().map(|i| i.balance.0).sum(); + let out_sum: RistrettoPoint = self.outputs.iter().map(|o| o.balance.0).sum(); out_sum - in_sum } @@ -169,7 +168,9 @@ impl PartialTx { #[cfg(test)] mod test { - use crate::{note::NoteWitness, nullifier::NullifierSecret, test_util::seed_rng, crypto::hash_to_curve}; + use crate::{ + crypto::hash_to_curve, note::NoteWitness, nullifier::NullifierSecret, test_util::seed_rng, + }; use super::*; @@ -223,8 +224,15 @@ mod test { assert_eq!( ptx.balance(), crate::balance::balance(4840, hash_to_curve(b"CRV"), crv_4840.note.balance.blinding) - - (crate::balance::balance(10, hash_to_curve(b"NMO"), nmo_10.note.balance.blinding) - + crate::balance::balance(23, hash_to_curve(b"ETH"), eth_23.note.balance.blinding)) + - (crate::balance::balance( + 10, + hash_to_curve(b"NMO"), + nmo_10.note.balance.blinding + ) + crate::balance::balance( + 23, + hash_to_curve(b"ETH"), + eth_23.note.balance.blinding + )) ); } } diff --git a/goas/Cargo.toml b/goas/Cargo.toml index b192d63..229aa89 100644 --- a/goas/Cargo.toml +++ b/goas/Cargo.toml @@ -13,6 +13,6 @@ lto = true [patch.crates-io] # Placing these patch statement in the workspace Cargo.toml will add RISC Zero SHA-256 and bigint # multiplication accelerator support for all downstream usages of the following crates. -sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } -k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.3-risczero.0" } -crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.2-risczero.0" } +#sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } +#k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.3-risczero.0" } +#crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.5-risczero.0" } diff --git a/goas/methods/guest/Cargo.toml b/goas/methods/guest/Cargo.toml index 013102a..077d9bf 100644 --- a/goas/methods/guest/Cargo.toml +++ b/goas/methods/guest/Cargo.toml @@ -21,4 +21,5 @@ cl = { path = "../../../cl" } # multiplication accelerator support for all downstream usages of the following crates. sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.3-risczero.0" } -crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.2-risczero.0" } +crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.5-risczero.0" } +curve25519-dalek = { git = "https://github.com/risc0/curve25519-dalek", tag = "curve25519-4.1.2-risczero.0" }