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"
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"

View File

@ -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<String>, rng: impl RngCore) -> Self {
Self::new(value, unit, Scalar::random(rng))
pub fn random(value: u64, unit: impl Into<String>, 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!(

View File

@ -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));

View File

@ -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::<ExpandMsgXmd<Sha256>>(&[bytes], &[b"NOMOS_HASH_TO_CURVE"]).unwrap()
pub fn hash_to_curve(bytes: &[u8]) -> RistrettoPoint {
RistrettoPoint::hash_from_bytes::<Blake2b512>(bytes)
}

View File

@ -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
}
}

View File

@ -1,5 +1,5 @@
use blake2::{Blake2s256, Digest};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
pub fn padded_leaves<const N: usize>(elements: &[Vec<u8>]) -> [[u8; 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] {
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);

View File

@ -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<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 {
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

View File

@ -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
}
}

View File

@ -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
))
);
}
}

View File

@ -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" }

View File

@ -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" }