switch to curve25519-dalek

This commit is contained in:
Giacomo Pasini 2024-07-03 11:44:48 +02:00
parent 8205f027db
commit bf25df4c6e
No known key found for this signature in database
GPG Key ID: FC08489D2D895D4B
11 changed files with 98 additions and 70 deletions

View File

@ -16,6 +16,6 @@ rand_core = "0.6.0"
rand_chacha = "0.3.1" rand_chacha = "0.3.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
hex = "0.4.3" 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"

View File

@ -1,33 +1,25 @@
use curve25519_dalek::{ristretto::RistrettoPoint, traits::VartimeMultiscalarMul, Scalar};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rand_core::RngCore; use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use k256::{
elliptic_curve::{
group::GroupEncoding, Field
},
ProjectivePoint, Scalar, AffinePoint
};
use k256::elliptic_curve::ops::LinearCombinationExt;
lazy_static! { lazy_static! {
// Precompute of `crate::crypto::hash_to_curve(b"NOMOS_CL_PEDERSON_COMMITMENT_BLINDING")` // Precompute of ``
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(); 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)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Balance(pub AffinePoint); pub struct Balance(pub RistrettoPoint);
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct BalanceWitness { pub struct BalanceWitness {
pub value: u64, pub value: u64,
pub unit: AffinePoint, pub unit: RistrettoPoint,
pub blinding: Scalar, pub blinding: Scalar,
} }
impl Balance { impl Balance {
pub fn to_bytes(&self) -> [u8; 33] { pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes().into() self.0.compress().to_bytes().into()
} }
} }
@ -40,8 +32,8 @@ impl BalanceWitness {
} }
} }
pub fn random(value: u64, unit: impl Into<String>, rng: impl RngCore) -> Self { pub fn random(value: u64, unit: impl Into<String>, mut rng: impl CryptoRngCore) -> Self {
Self::new(value, unit, Scalar::random(rng)) Self::new(value, unit, Scalar::random(&mut rng))
} }
pub fn commit(&self) -> Balance { 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()) 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); 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 { // mod serde_scalar {
@ -152,16 +148,19 @@ pub fn balance(value: u64, unit: ProjectivePoint, blinding: Scalar) -> Projectiv
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
use crate::test_util::seed_rng; use crate::test_util::seed_rng;
use k256::elliptic_curve::group::prime::PrimeCurveAffine; use k256::elliptic_curve::group::prime::PrimeCurveAffine;
use super::*;
#[test] #[test]
fn test_pederson_blinding_point_pre_compute() { fn test_pederson_blinding_point_pre_compute() {
// use k256::elliptic_curve::group::GroupEncoding; // use k256::elliptic_curve::group::GroupEncoding;
// println!("{:?}", <[u8;33]>::from((*PEDERSON_COMMITMENT_BLINDING_POINT).to_bytes())); // 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] #[test]
@ -185,7 +184,10 @@ mod test {
let a = a_w.commit(); let a = a_w.commit();
let b = b_w.commit(); let b = b_w.commit();
assert_ne!(a, b); 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] #[test]
@ -207,7 +209,10 @@ mod test {
let two = BalanceWitness::new(2, "NMO", 0u32.into()); let two = BalanceWitness::new(2, "NMO", 0u32.into());
// Values of same unit are homomorphic // 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. // Blinding factors are also homomorphic.
assert_eq!( assert_eq!(

View File

@ -2,7 +2,7 @@ use std::collections::BTreeSet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use k256::{Scalar, ProjectivePoint}; use curve25519_dalek::{constants::RISTRETTO_BASEPOINT_POINT, ristretto::RistrettoPoint, Scalar};
use crate::{ use crate::{
error::Error, error::Error,
@ -31,12 +31,13 @@ pub struct BundleProof {
} }
impl Bundle { impl Bundle {
pub fn balance(&self) -> ProjectivePoint { pub fn balance(&self) -> RistrettoPoint {
self.partials.iter().map(|ptx| ptx.balance()).sum() self.partials.iter().map(|ptx| ptx.balance()).sum()
} }
pub fn is_balanced(&self, balance_blinding_witness: Scalar) -> bool { 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( pub fn prove(
@ -65,7 +66,9 @@ impl Bundle {
return Err(Error::ProofFailed); 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); return Err(Error::ProofFailed);
} }
@ -89,9 +92,8 @@ impl Bundle {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{ use crate::{
input::InputWitness, note::NoteWitness, nullifier::NullifierSecret, output::OutputWitness, crypto::hash_to_curve, input::InputWitness, note::NoteWitness, nullifier::NullifierSecret,
partial_tx::PartialTxWitness, test_util::seed_rng, output::OutputWitness, partial_tx::PartialTxWitness, test_util::seed_rng,
crypto::hash_to_curve,
}; };
use super::*; use super::*;
@ -128,9 +130,19 @@ mod test {
assert!(!bundle.is_balanced(bundle_witness.balance_blinding)); assert!(!bundle.is_balanced(bundle_witness.balance_blinding));
assert_eq!( assert_eq!(
bundle.balance(), bundle.balance(),
crate::balance::balance(4840, hash_to_curve(b"CRV"), crv_4840_out.note.balance.blinding) crate::balance::balance(
- (crate::balance::balance(10, hash_to_curve(b"NMO"), nmo_10_in.note.balance.blinding) 4840,
+ crate::balance::balance(23, hash_to_curve(b"ETH"), eth_23_in.note.balance.blinding)) 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 = let crv_4840_in =
@ -163,7 +175,7 @@ mod test {
assert_eq!( assert_eq!(
bundle.balance(), 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)); assert!(bundle.is_balanced(witness.balance_blinding));

View File

@ -1,8 +1,6 @@
use k256::{Secp256k1, ProjectivePoint, elliptic_curve::{ use blake2::Blake2b512;
hash2curve::{GroupDigest, ExpandMsgXmd}, use curve25519_dalek::ristretto::RistrettoPoint;
},sha2::Sha256
};
pub fn hash_to_curve(bytes: &[u8]) -> ProjectivePoint { pub fn hash_to_curve(bytes: &[u8]) -> RistrettoPoint {
Secp256k1::hash_from_bytes::<ExpandMsgXmd<Sha256>>(&[bytes], &[b"NOMOS_HASH_TO_CURVE"]).unwrap() RistrettoPoint::hash_from_bytes::<Blake2b512>(bytes)
} }

View File

@ -105,11 +105,11 @@ impl Input {
&& death_constraint_is_satisfied && death_constraint_is_satisfied
} }
pub fn to_bytes(&self) -> [u8; 97] { pub fn to_bytes(&self) -> [u8; 96] {
let mut bytes = [0u8; 97]; let mut bytes = [0u8; 96];
bytes[..32].copy_from_slice(self.note_comm.as_bytes()); bytes[..32].copy_from_slice(self.note_comm.as_bytes());
bytes[32..64].copy_from_slice(self.nullifier.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 bytes
} }
} }

View File

@ -1,5 +1,5 @@
use blake2::{Blake2s256, Digest};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
pub fn padded_leaves<const N: usize>(elements: &[Vec<u8>]) -> [[u8; 32]; N] { pub fn padded_leaves<const N: usize>(elements: &[Vec<u8>]) -> [[u8; 32]; N] {
let mut leaves = [[0u8; 32]; N]; let mut leaves = [[0u8; 32]; N];
@ -13,14 +13,14 @@ pub fn padded_leaves<const N: usize>(elements: &[Vec<u8>]) -> [[u8; 32]; N] {
} }
pub fn leaf(data: &[u8]) -> [u8; 32] { 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(b"NOMOS_MERKLE_LEAF");
hasher.update(data); hasher.update(data);
hasher.finalize().into() hasher.finalize().into()
} }
pub fn node(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { 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(b"NOMOS_MERKLE_NODE");
hasher.update(a); hasher.update(a);
hasher.update(b); hasher.update(b);

View File

@ -1,7 +1,6 @@
use blake2::{Blake2s256, Digest}; use blake2::{Blake2s256, Digest};
use rand_core::RngCore; use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use k256::elliptic_curve::group::GroupEncoding;
use crate::{ use crate::{
balance::{Balance, BalanceWitness}, balance::{Balance, BalanceWitness},
@ -27,7 +26,12 @@ pub struct NoteWitness {
} }
impl NoteWitness { impl NoteWitness {
pub fn new(value: u64, unit: impl Into<String>, state: [u8; 32], rng: impl RngCore) -> Self { pub fn new(
value: u64,
unit: impl Into<String>,
state: [u8; 32],
rng: impl CryptoRngCore,
) -> Self {
Self { Self {
balance: BalanceWitness::random(value, unit, rng), balance: BalanceWitness::random(value, unit, rng),
death_constraint: vec![], death_constraint: vec![],
@ -41,7 +45,7 @@ impl NoteWitness {
// COMMIT TO BALANCE // COMMIT TO BALANCE
hasher.update(self.balance.value.to_le_bytes()); 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. // Important! we don't commit to the balance blinding factor as that may make the notes linkable.
// COMMIT TO STATE // COMMIT TO STATE

View File

@ -61,10 +61,10 @@ impl Output {
&& self.balance == witness.note.balance() && self.balance == witness.note.balance()
} }
pub fn to_bytes(&self) -> [u8; 65] { pub fn to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 65]; let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(self.note_comm.as_bytes()); 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 bytes
} }
} }

View File

@ -2,9 +2,8 @@ use std::collections::BTreeSet;
use rand_core::RngCore; use rand_core::RngCore;
// use risc0_groth16::ProofJson; // use risc0_groth16::ProofJson;
use curve25519_dalek::ristretto::RistrettoPoint;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use k256::ProjectivePoint;
use k256::elliptic_curve::group::prime::PrimeCurveAffine;
use crate::error::Error; use crate::error::Error;
use crate::input::{Input, InputProof, InputWitness}; use crate::input::{Input, InputProof, InputWitness};
@ -158,9 +157,9 @@ impl PartialTx {
.all(|(o, p)| o.verify(p)) .all(|(o, p)| o.verify(p))
} }
pub fn balance(&self) -> ProjectivePoint { pub fn balance(&self) -> RistrettoPoint {
let in_sum: ProjectivePoint = self.inputs.iter().map(|i| i.balance.0.to_curve()).sum(); let in_sum: RistrettoPoint = self.inputs.iter().map(|i| i.balance.0).sum();
let out_sum: ProjectivePoint = self.outputs.iter().map(|o| o.balance.0.to_curve()).sum(); let out_sum: RistrettoPoint = self.outputs.iter().map(|o| o.balance.0).sum();
out_sum - in_sum out_sum - in_sum
} }
@ -169,7 +168,9 @@ impl PartialTx {
#[cfg(test)] #[cfg(test)]
mod 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::*; use super::*;
@ -223,8 +224,15 @@ mod test {
assert_eq!( assert_eq!(
ptx.balance(), ptx.balance(),
crate::balance::balance(4840, hash_to_curve(b"CRV"), crv_4840.note.balance.blinding) 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(
+ crate::balance::balance(23, hash_to_curve(b"ETH"), eth_23.note.balance.blinding)) 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
))
); );
} }
} }

View File

@ -13,6 +13,6 @@ lto = true
[patch.crates-io] [patch.crates-io]
# Placing these patch statement in the workspace Cargo.toml will add RISC Zero SHA-256 and bigint # 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. # 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" } #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" } #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" }

View File

@ -21,4 +21,5 @@ cl = { path = "../../../cl" }
# multiplication accelerator support for all downstream usages of the following crates. # 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" } 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" } 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" }