From 5d9944a27834d1269bf3d4d6bb007a2e26960ecd Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 02:33:24 +0400 Subject: [PATCH 01/17] extract curve25519 crate --- Cargo.lock | 10 + Cargo.toml | 2 + curve25519/.gitignore | 1 + curve25519/Cargo.toml | 18 ++ curve25519/src/curve_syscall_traits.rs | 85 ++++++ curve25519/src/edwards.rs | 381 ++++++++++++++++++++++++ curve25519/src/errors.rs | 7 + curve25519/src/lib.rs | 11 + curve25519/src/ristretto.rs | 386 +++++++++++++++++++++++++ curve25519/src/scalar.rs | 24 ++ 10 files changed, 925 insertions(+) create mode 100644 curve25519/.gitignore create mode 100644 curve25519/Cargo.toml create mode 100644 curve25519/src/curve_syscall_traits.rs create mode 100644 curve25519/src/edwards.rs create mode 100644 curve25519/src/errors.rs create mode 100644 curve25519/src/lib.rs create mode 100644 curve25519/src/ristretto.rs create mode 100644 curve25519/src/scalar.rs diff --git a/Cargo.lock b/Cargo.lock index bbe100e5a19394..e7b66aec56fb28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5529,6 +5529,16 @@ dependencies = [ "sha-1 0.9.8", ] +[[package]] +name = "solana--curve25519" +version = "0.0.1" +dependencies = [ + "bytemuck", + "curve25519-dalek", + "solana-program", + "thiserror", +] + [[package]] name = "solana-account-decoder" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 50347b0958ea7b..80f340868827f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -128,6 +128,7 @@ members = [ "wen-restart", "zk-keygen", "zk-sdk", + "curve25519", "zk-token-sdk", ] @@ -405,6 +406,7 @@ solana-wen-restart = { path = "wen-restart", version = "=2.0.0" } solana-zk-elgamal-proof-program = { path = "programs/zk-elgamal-proof", version = "=2.0.0" } solana-zk-keygen = { path = "zk-keygen", version = "=2.0.0" } solana-zk-sdk = { path = "zk-sdk", version = "=2.0.0" } +solana-curve25519 = { path = "zk-token-curve25519", version = "=0.0.1" } solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=2.0.0" } solana-zk-token-sdk = { path = "zk-token-sdk", version = "=2.0.0" } solana_rbpf = "=0.8.1" diff --git a/curve25519/.gitignore b/curve25519/.gitignore new file mode 100644 index 00000000000000..b645148aa9118c --- /dev/null +++ b/curve25519/.gitignore @@ -0,0 +1 @@ +/farf/ diff --git a/curve25519/Cargo.toml b/curve25519/Cargo.toml new file mode 100644 index 00000000000000..50ab8bdba86de7 --- /dev/null +++ b/curve25519/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "solana--curve25519" +description = "Solana Curve25519 Syscalls" +documentation = "https://docs.rs/solana-curve25519" +version = "0.0.1" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] +bytemuck = { workspace = true, features = ["derive"] } +solana-program = { workspace = true } +thiserror = { workspace = true } + +[target.'cfg(not(target_os = "solana"))'.dependencies] +curve25519-dalek = { workspace = true, features = ["serde"] } diff --git a/curve25519/src/curve_syscall_traits.rs b/curve25519/src/curve_syscall_traits.rs new file mode 100644 index 00000000000000..547f6c948d7cf0 --- /dev/null +++ b/curve25519/src/curve_syscall_traits.rs @@ -0,0 +1,85 @@ +//! The traits representing the basic elliptic curve operations. +//! +//! These traits are instantiatable by all the commonly used elliptic curves and should help in +//! organizing syscall support for other curves in the future. more complicated or curve-specific +//! functions that are needed in cryptographic applications should be representable by combining +//! the associated functions of these traits. +//! +//! NOTE: This module temporarily lives in zk_token_sdk/curve25519, but it is independent of +//! zk-token-sdk or curve25519. It should be moved to a more general location in the future. +//! + +// Functions are organized by the curve traits, which can be instantiated by multiple curve +// representations. The functions take in a `curve_id` (e.g. `CURVE25519_EDWARDS`) and should run +// the associated functions in the appropriate trait instantiation. The `curve_op` function +// additionally takes in an `op_id` (e.g. `ADD`) that controls which associated functions to run in +// `GroupOperations`. + +pub trait PointValidation { + type Point; + + /// Verifies if a byte representation of a curve point lies in the curve. + fn validate_point(&self) -> bool; +} + +pub trait GroupOperations { + type Point; + type Scalar; + + /// Adds two curve points: P_0 + P_1. + fn add(left_point: &Self::Point, right_point: &Self::Point) -> Option; + + /// Subtracts two curve points: P_0 - P_1. + /// + /// NOTE: Altneratively, one can consider replacing this with a `negate` function that maps a + /// curve point P -> -P. Then subtraction can be computed by combining `negate` and `add` + /// syscalls. However, `subtract` is a much more widely used function than `negate`. + fn subtract(left_point: &Self::Point, right_point: &Self::Point) -> Option; + + /// Multiplies a scalar S with a curve point P: S*P + fn multiply(scalar: &Self::Scalar, point: &Self::Point) -> Option; +} + +pub trait MultiScalarMultiplication { + type Scalar; + type Point; + + /// Given a vector of scalsrs S_1, ..., S_N, and curve points P_1, ..., P_N, computes the + /// "inner product": S_1*P_1 + ... + S_N*P_N. + /// + /// NOTE: This operation can be represented by combining `add` and `multiply` functions in + /// `GroupOperations`, but computing it in a single batch is significantly cheaper. Given how + /// commonly used the multiscalar multiplication (MSM) is, it seems to make sense to have a + /// designated trait for MSM support. + /// + /// NOTE: The inputs to the function is a non-fixed size vector and hence, there are some + /// complications in computing the cost for the syscall. The computational costs should only + /// depend on the length of the vectors (and the curve), so it would be ideal to support + /// variable length inputs and compute the syscall cost as is done in eip-197: + /// . If not, then we can + /// consider bounding the length of the input and assigning worst-case cost. + fn multiscalar_multiply( + scalars: &[Self::Scalar], + points: &[Self::Point], + ) -> Option; +} + +pub trait Pairing { + type G1Point; + type G2Point; + type GTPoint; + + /// Applies the bilinear pairing operation to two curve points P1, P2 -> e(P1, P2). This trait + /// is only relevant for "pairing-friendly" curves such as BN254 and BLS12-381. + fn pairing_map( + left_point: &Self::G1Point, + right_point: &Self::G2Point, + ) -> Option; +} + +pub const CURVE25519_EDWARDS: u64 = 0; +pub const CURVE25519_RISTRETTO: u64 = 1; + +pub const ADD: u64 = 0; +pub const SUB: u64 = 1; +pub const MUL: u64 = 2; diff --git a/curve25519/src/edwards.rs b/curve25519/src/edwards.rs new file mode 100644 index 00000000000000..0dd019b1910d0a --- /dev/null +++ b/curve25519/src/edwards.rs @@ -0,0 +1,381 @@ +use bytemuck::{Pod, Zeroable}; +pub use target_arch::*; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)] +#[repr(transparent)] +pub struct PodEdwardsPoint(pub [u8; 32]); + +#[cfg(not(target_os = "solana"))] +mod target_arch { + use { + super::*, + crate::curve25519::{ + curve_syscall_traits::{GroupOperations, MultiScalarMultiplication, PointValidation}, + errors::Curve25519Error, + scalar::PodScalar, + }, + curve25519_dalek::{ + edwards::{CompressedEdwardsY, EdwardsPoint}, + scalar::Scalar, + traits::VartimeMultiscalarMul, + }, + }; + + pub fn validate_edwards(point: &PodEdwardsPoint) -> bool { + point.validate_point() + } + + pub fn add_edwards( + left_point: &PodEdwardsPoint, + right_point: &PodEdwardsPoint, + ) -> Option { + PodEdwardsPoint::add(left_point, right_point) + } + + pub fn subtract_edwards( + left_point: &PodEdwardsPoint, + right_point: &PodEdwardsPoint, + ) -> Option { + PodEdwardsPoint::subtract(left_point, right_point) + } + + pub fn multiply_edwards( + scalar: &PodScalar, + point: &PodEdwardsPoint, + ) -> Option { + PodEdwardsPoint::multiply(scalar, point) + } + + pub fn multiscalar_multiply_edwards( + scalars: &[PodScalar], + points: &[PodEdwardsPoint], + ) -> Option { + PodEdwardsPoint::multiscalar_multiply(scalars, points) + } + + impl From<&EdwardsPoint> for PodEdwardsPoint { + fn from(point: &EdwardsPoint) -> Self { + Self(point.compress().to_bytes()) + } + } + + impl TryFrom<&PodEdwardsPoint> for EdwardsPoint { + type Error = Curve25519Error; + + fn try_from(pod: &PodEdwardsPoint) -> Result { + CompressedEdwardsY::from_slice(&pod.0) + .decompress() + .ok_or(Curve25519Error::PodConversion) + } + } + + impl PointValidation for PodEdwardsPoint { + type Point = Self; + + fn validate_point(&self) -> bool { + CompressedEdwardsY::from_slice(&self.0) + .decompress() + .is_some() + } + } + + impl GroupOperations for PodEdwardsPoint { + type Scalar = PodScalar; + type Point = Self; + + fn add(left_point: &Self, right_point: &Self) -> Option { + let left_point: EdwardsPoint = left_point.try_into().ok()?; + let right_point: EdwardsPoint = right_point.try_into().ok()?; + + let result = &left_point + &right_point; + Some((&result).into()) + } + + fn subtract(left_point: &Self, right_point: &Self) -> Option { + let left_point: EdwardsPoint = left_point.try_into().ok()?; + let right_point: EdwardsPoint = right_point.try_into().ok()?; + + let result = &left_point - &right_point; + Some((&result).into()) + } + + #[cfg(not(target_os = "solana"))] + fn multiply(scalar: &PodScalar, point: &Self) -> Option { + let scalar: Scalar = scalar.try_into().ok()?; + let point: EdwardsPoint = point.try_into().ok()?; + + let result = &scalar * &point; + Some((&result).into()) + } + } + + impl MultiScalarMultiplication for PodEdwardsPoint { + type Scalar = PodScalar; + type Point = Self; + + fn multiscalar_multiply(scalars: &[PodScalar], points: &[Self]) -> Option { + let scalars = scalars + .iter() + .map(|scalar| Scalar::try_from(scalar).ok()) + .collect::>>()?; + + EdwardsPoint::optional_multiscalar_mul( + scalars, + points + .iter() + .map(|point| EdwardsPoint::try_from(point).ok()), + ) + .map(|result| PodEdwardsPoint::from(&result)) + } + } +} + +#[cfg(target_os = "solana")] +mod target_arch { + use { + super::*, + crate::curve25519::{ + curve_syscall_traits::{ADD, CURVE25519_EDWARDS, MUL, SUB}, + scalar::PodScalar, + }, + }; + + pub fn validate_edwards(point: &PodEdwardsPoint) -> bool { + let mut validate_result = 0u8; + let result = unsafe { + solana_program::syscalls::sol_curve_validate_point( + CURVE25519_EDWARDS, + &point.0 as *const u8, + &mut validate_result, + ) + }; + result == 0 + } + + pub fn add_edwards( + left_point: &PodEdwardsPoint, + right_point: &PodEdwardsPoint, + ) -> Option { + let mut result_point = PodEdwardsPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_group_op( + CURVE25519_EDWARDS, + ADD, + &left_point.0 as *const u8, + &right_point.0 as *const u8, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } + + pub fn subtract_edwards( + left_point: &PodEdwardsPoint, + right_point: &PodEdwardsPoint, + ) -> Option { + let mut result_point = PodEdwardsPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_group_op( + CURVE25519_EDWARDS, + SUB, + &left_point.0 as *const u8, + &right_point.0 as *const u8, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } + + pub fn multiply_edwards( + scalar: &PodScalar, + point: &PodEdwardsPoint, + ) -> Option { + let mut result_point = PodEdwardsPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_group_op( + CURVE25519_EDWARDS, + MUL, + &scalar.0 as *const u8, + &point.0 as *const u8, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } + + pub fn multiscalar_multiply_edwards( + scalars: &[PodScalar], + points: &[PodEdwardsPoint], + ) -> Option { + let mut result_point = PodEdwardsPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_multiscalar_mul( + CURVE25519_EDWARDS, + scalars.as_ptr() as *const u8, + points.as_ptr() as *const u8, + points.len() as u64, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::curve25519::scalar::PodScalar, + curve25519_dalek::{ + constants::ED25519_BASEPOINT_POINT as G, edwards::EdwardsPoint, traits::Identity, + }, + }; + + #[test] + fn test_validate_edwards() { + let pod = PodEdwardsPoint(G.compress().to_bytes()); + assert!(validate_edwards(&pod)); + + let invalid_bytes = [ + 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84, + 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79, + ]; + + assert!(!validate_edwards(&PodEdwardsPoint(invalid_bytes))); + } + + #[test] + fn test_edwards_add_subtract() { + // identity + let identity = PodEdwardsPoint(EdwardsPoint::identity().compress().to_bytes()); + let point = PodEdwardsPoint([ + 201, 179, 241, 122, 180, 185, 239, 50, 183, 52, 221, 0, 153, 195, 43, 18, 22, 38, 187, + 206, 179, 192, 210, 58, 53, 45, 150, 98, 89, 17, 158, 11, + ]); + + assert_eq!(add_edwards(&point, &identity).unwrap(), point); + assert_eq!(subtract_edwards(&point, &identity).unwrap(), point); + + // associativity + let point_a = PodEdwardsPoint([ + 33, 124, 71, 170, 117, 69, 151, 247, 59, 12, 95, 125, 133, 166, 64, 5, 2, 27, 90, 27, + 200, 167, 59, 164, 52, 54, 52, 200, 29, 13, 34, 213, + ]); + let point_b = PodEdwardsPoint([ + 70, 222, 137, 221, 253, 204, 71, 51, 78, 8, 124, 1, 67, 200, 102, 225, 122, 228, 111, + 183, 129, 14, 131, 210, 212, 95, 109, 246, 55, 10, 159, 91, + ]); + let point_c = PodEdwardsPoint([ + 72, 60, 66, 143, 59, 197, 111, 36, 181, 137, 25, 97, 157, 201, 247, 215, 123, 83, 220, + 250, 154, 150, 180, 192, 196, 28, 215, 137, 34, 247, 39, 129, + ]); + + assert_eq!( + add_edwards(&add_edwards(&point_a, &point_b).unwrap(), &point_c), + add_edwards(&point_a, &add_edwards(&point_b, &point_c).unwrap()), + ); + + assert_eq!( + subtract_edwards(&subtract_edwards(&point_a, &point_b).unwrap(), &point_c), + subtract_edwards(&point_a, &add_edwards(&point_b, &point_c).unwrap()), + ); + + // commutativity + assert_eq!( + add_edwards(&point_a, &point_b).unwrap(), + add_edwards(&point_b, &point_a).unwrap(), + ); + + // subtraction + let point = PodEdwardsPoint(G.compress().to_bytes()); + let point_negated = PodEdwardsPoint((-G).compress().to_bytes()); + + assert_eq!(point_negated, subtract_edwards(&identity, &point).unwrap(),) + } + + #[test] + fn test_edwards_mul() { + let scalar_a = PodScalar([ + 72, 191, 131, 55, 85, 86, 54, 60, 116, 10, 39, 130, 180, 3, 90, 227, 47, 228, 252, 99, + 151, 71, 118, 29, 34, 102, 117, 114, 120, 50, 57, 8, + ]); + let point_x = PodEdwardsPoint([ + 176, 121, 6, 191, 108, 161, 206, 141, 73, 14, 235, 97, 49, 68, 48, 112, 98, 215, 145, + 208, 44, 188, 70, 10, 180, 124, 230, 15, 98, 165, 104, 85, + ]); + let point_y = PodEdwardsPoint([ + 174, 86, 89, 208, 236, 123, 223, 128, 75, 54, 228, 232, 220, 100, 205, 108, 237, 97, + 105, 79, 74, 192, 67, 224, 185, 23, 157, 116, 216, 151, 223, 81, + ]); + + let ax = multiply_edwards(&scalar_a, &point_x).unwrap(); + let bx = multiply_edwards(&scalar_a, &point_y).unwrap(); + + assert_eq!( + add_edwards(&ax, &bx), + multiply_edwards(&scalar_a, &add_edwards(&point_x, &point_y).unwrap()), + ); + } + + #[test] + fn test_multiscalar_multiplication_edwards() { + let scalar = PodScalar([ + 205, 73, 127, 173, 83, 80, 190, 66, 202, 3, 237, 77, 52, 223, 238, 70, 80, 242, 24, 87, + 111, 84, 49, 63, 194, 76, 202, 108, 62, 240, 83, 15, + ]); + let point = PodEdwardsPoint([ + 222, 174, 184, 139, 143, 122, 253, 96, 0, 207, 120, 157, 112, 38, 54, 189, 91, 144, 78, + 111, 111, 122, 140, 183, 65, 250, 191, 133, 6, 42, 212, 93, + ]); + + let basic_product = multiply_edwards(&scalar, &point).unwrap(); + let msm_product = multiscalar_multiply_edwards(&[scalar], &[point]).unwrap(); + + assert_eq!(basic_product, msm_product); + + let scalar_a = PodScalar([ + 246, 154, 34, 110, 31, 185, 50, 1, 252, 194, 163, 56, 211, 18, 101, 192, 57, 225, 207, + 69, 19, 84, 231, 118, 137, 175, 148, 218, 106, 212, 69, 9, + ]); + let scalar_b = PodScalar([ + 27, 58, 126, 136, 253, 178, 176, 245, 246, 55, 15, 202, 35, 183, 66, 199, 134, 187, + 169, 154, 66, 120, 169, 193, 75, 4, 33, 241, 126, 227, 59, 3, + ]); + let point_x = PodEdwardsPoint([ + 252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168, + 53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133, + ]); + let point_y = PodEdwardsPoint([ + 10, 111, 8, 236, 97, 189, 124, 69, 89, 176, 222, 39, 199, 253, 111, 11, 248, 186, 128, + 90, 120, 128, 248, 210, 232, 183, 93, 104, 111, 150, 7, 241, + ]); + + let ax = multiply_edwards(&scalar_a, &point_x).unwrap(); + let by = multiply_edwards(&scalar_b, &point_y).unwrap(); + let basic_product = add_edwards(&ax, &by).unwrap(); + let msm_product = + multiscalar_multiply_edwards(&[scalar_a, scalar_b], &[point_x, point_y]).unwrap(); + + assert_eq!(basic_product, msm_product); + } +} diff --git a/curve25519/src/errors.rs b/curve25519/src/errors.rs new file mode 100644 index 00000000000000..2aabc732a39006 --- /dev/null +++ b/curve25519/src/errors.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Clone, Debug, Eq, PartialEq)] +pub enum Curve25519Error { + #[error("pod conversion failed")] + PodConversion, +} diff --git a/curve25519/src/lib.rs b/curve25519/src/lib.rs new file mode 100644 index 00000000000000..19c4aa1388aa9a --- /dev/null +++ b/curve25519/src/lib.rs @@ -0,0 +1,11 @@ +//! Syscall operations for curve25519 +//! +//! This module lives inside the zk-token-sdk for now, but should move to a general location since +//! it is independent of zk-tokens. + +pub mod curve_syscall_traits; +pub mod edwards; +#[cfg(not(target_os = "solana"))] +pub mod errors; +pub mod ristretto; +pub mod scalar; diff --git a/curve25519/src/ristretto.rs b/curve25519/src/ristretto.rs new file mode 100644 index 00000000000000..772441a32aa65f --- /dev/null +++ b/curve25519/src/ristretto.rs @@ -0,0 +1,386 @@ +use bytemuck::{Pod, Zeroable}; +pub use target_arch::*; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)] +#[repr(transparent)] +pub struct PodRistrettoPoint(pub [u8; 32]); + +#[cfg(not(target_os = "solana"))] +mod target_arch { + use { + super::*, + crate::curve25519::{ + curve_syscall_traits::{GroupOperations, MultiScalarMultiplication, PointValidation}, + errors::Curve25519Error, + scalar::PodScalar, + }, + curve25519_dalek::{ + ristretto::{CompressedRistretto, RistrettoPoint}, + scalar::Scalar, + traits::VartimeMultiscalarMul, + }, + }; + + pub fn validate_ristretto(point: &PodRistrettoPoint) -> bool { + point.validate_point() + } + + pub fn add_ristretto( + left_point: &PodRistrettoPoint, + right_point: &PodRistrettoPoint, + ) -> Option { + PodRistrettoPoint::add(left_point, right_point) + } + + pub fn subtract_ristretto( + left_point: &PodRistrettoPoint, + right_point: &PodRistrettoPoint, + ) -> Option { + PodRistrettoPoint::subtract(left_point, right_point) + } + + pub fn multiply_ristretto( + scalar: &PodScalar, + point: &PodRistrettoPoint, + ) -> Option { + PodRistrettoPoint::multiply(scalar, point) + } + + pub fn multiscalar_multiply_ristretto( + scalars: &[PodScalar], + points: &[PodRistrettoPoint], + ) -> Option { + PodRistrettoPoint::multiscalar_multiply(scalars, points) + } + + impl From<&RistrettoPoint> for PodRistrettoPoint { + fn from(point: &RistrettoPoint) -> Self { + Self(point.compress().to_bytes()) + } + } + + impl TryFrom<&PodRistrettoPoint> for RistrettoPoint { + type Error = Curve25519Error; + + fn try_from(pod: &PodRistrettoPoint) -> Result { + CompressedRistretto::from_slice(&pod.0) + .decompress() + .ok_or(Curve25519Error::PodConversion) + } + } + + impl PointValidation for PodRistrettoPoint { + type Point = Self; + + fn validate_point(&self) -> bool { + CompressedRistretto::from_slice(&self.0) + .decompress() + .is_some() + } + } + + impl GroupOperations for PodRistrettoPoint { + type Scalar = PodScalar; + type Point = Self; + + fn add(left_point: &Self, right_point: &Self) -> Option { + let left_point: RistrettoPoint = left_point.try_into().ok()?; + let right_point: RistrettoPoint = right_point.try_into().ok()?; + + let result = &left_point + &right_point; + Some((&result).into()) + } + + fn subtract(left_point: &Self, right_point: &Self) -> Option { + let left_point: RistrettoPoint = left_point.try_into().ok()?; + let right_point: RistrettoPoint = right_point.try_into().ok()?; + + let result = &left_point - &right_point; + Some((&result).into()) + } + + #[cfg(not(target_os = "solana"))] + fn multiply(scalar: &PodScalar, point: &Self) -> Option { + let scalar: Scalar = scalar.try_into().ok()?; + let point: RistrettoPoint = point.try_into().ok()?; + + let result = &scalar * &point; + Some((&result).into()) + } + } + + impl MultiScalarMultiplication for PodRistrettoPoint { + type Scalar = PodScalar; + type Point = Self; + + fn multiscalar_multiply(scalars: &[PodScalar], points: &[Self]) -> Option { + let scalars = scalars + .iter() + .map(|scalar| Scalar::try_from(scalar).ok()) + .collect::>>()?; + + RistrettoPoint::optional_multiscalar_mul( + scalars, + points + .iter() + .map(|point| RistrettoPoint::try_from(point).ok()), + ) + .map(|result| PodRistrettoPoint::from(&result)) + } + } +} + +#[cfg(target_os = "solana")] +#[allow(unused_variables)] +mod target_arch { + use { + super::*, + crate::curve25519::{ + curve_syscall_traits::{ADD, CURVE25519_RISTRETTO, MUL, SUB}, + scalar::PodScalar, + }, + }; + + pub fn validate_ristretto(point: &PodRistrettoPoint) -> bool { + let mut validate_result = 0u8; + let result = unsafe { + solana_program::syscalls::sol_curve_validate_point( + CURVE25519_RISTRETTO, + &point.0 as *const u8, + &mut validate_result, + ) + }; + + result == 0 + } + + pub fn add_ristretto( + left_point: &PodRistrettoPoint, + right_point: &PodRistrettoPoint, + ) -> Option { + let mut result_point = PodRistrettoPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_group_op( + CURVE25519_RISTRETTO, + ADD, + &left_point.0 as *const u8, + &right_point.0 as *const u8, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } + + pub fn subtract_ristretto( + left_point: &PodRistrettoPoint, + right_point: &PodRistrettoPoint, + ) -> Option { + let mut result_point = PodRistrettoPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_group_op( + CURVE25519_RISTRETTO, + SUB, + &left_point.0 as *const u8, + &right_point.0 as *const u8, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } + + pub fn multiply_ristretto( + scalar: &PodScalar, + point: &PodRistrettoPoint, + ) -> Option { + let mut result_point = PodRistrettoPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_group_op( + CURVE25519_RISTRETTO, + MUL, + &scalar.0 as *const u8, + &point.0 as *const u8, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } + + pub fn multiscalar_multiply_ristretto( + scalars: &[PodScalar], + points: &[PodRistrettoPoint], + ) -> Option { + let mut result_point = PodRistrettoPoint::zeroed(); + let result = unsafe { + solana_program::syscalls::sol_curve_multiscalar_mul( + CURVE25519_RISTRETTO, + scalars.as_ptr() as *const u8, + points.as_ptr() as *const u8, + points.len() as u64, + &mut result_point.0 as *mut u8, + ) + }; + + if result == 0 { + Some(result_point) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::curve25519::scalar::PodScalar, + curve25519_dalek::{ + constants::RISTRETTO_BASEPOINT_POINT as G, ristretto::RistrettoPoint, traits::Identity, + }, + }; + + #[test] + fn test_validate_ristretto() { + let pod = PodRistrettoPoint(G.compress().to_bytes()); + assert!(validate_ristretto(&pod)); + + let invalid_bytes = [ + 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84, + 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79, + ]; + + assert!(!validate_ristretto(&PodRistrettoPoint(invalid_bytes))); + } + + #[test] + fn test_add_subtract_ristretto() { + // identity + let identity = PodRistrettoPoint(RistrettoPoint::identity().compress().to_bytes()); + let point = PodRistrettoPoint([ + 210, 174, 124, 127, 67, 77, 11, 114, 71, 63, 168, 136, 113, 20, 141, 228, 195, 254, + 232, 229, 220, 249, 213, 232, 61, 238, 152, 249, 83, 225, 206, 16, + ]); + + assert_eq!(add_ristretto(&point, &identity).unwrap(), point); + assert_eq!(subtract_ristretto(&point, &identity).unwrap(), point); + + // associativity + let point_a = PodRistrettoPoint([ + 208, 165, 125, 204, 2, 100, 218, 17, 170, 194, 23, 9, 102, 156, 134, 136, 217, 190, 98, + 34, 183, 194, 228, 153, 92, 11, 108, 103, 28, 57, 88, 15, + ]); + let point_b = PodRistrettoPoint([ + 208, 241, 72, 163, 73, 53, 32, 174, 54, 194, 71, 8, 70, 181, 244, 199, 93, 147, 99, + 231, 162, 127, 25, 40, 39, 19, 140, 132, 112, 212, 145, 108, + ]); + let point_c = PodRistrettoPoint([ + 250, 61, 200, 25, 195, 15, 144, 179, 24, 17, 252, 167, 247, 44, 47, 41, 104, 237, 49, + 137, 231, 173, 86, 106, 121, 249, 245, 247, 70, 188, 31, 49, + ]); + + assert_eq!( + add_ristretto(&add_ristretto(&point_a, &point_b).unwrap(), &point_c), + add_ristretto(&point_a, &add_ristretto(&point_b, &point_c).unwrap()), + ); + + assert_eq!( + subtract_ristretto(&subtract_ristretto(&point_a, &point_b).unwrap(), &point_c), + subtract_ristretto(&point_a, &add_ristretto(&point_b, &point_c).unwrap()), + ); + + // commutativity + assert_eq!( + add_ristretto(&point_a, &point_b).unwrap(), + add_ristretto(&point_b, &point_a).unwrap(), + ); + + // subtraction + let point = PodRistrettoPoint(G.compress().to_bytes()); + let point_negated = PodRistrettoPoint((-G).compress().to_bytes()); + + assert_eq!( + point_negated, + subtract_ristretto(&identity, &point).unwrap(), + ) + } + + #[test] + fn test_multiply_ristretto() { + let scalar_x = PodScalar([ + 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250, + 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6, + ]); + let point_a = PodRistrettoPoint([ + 68, 80, 232, 181, 241, 77, 60, 81, 154, 51, 173, 35, 98, 234, 149, 37, 1, 39, 191, 201, + 193, 48, 88, 189, 97, 126, 63, 35, 144, 145, 203, 31, + ]); + let point_b = PodRistrettoPoint([ + 200, 236, 1, 12, 244, 130, 226, 214, 28, 125, 43, 163, 222, 234, 81, 213, 201, 156, 31, + 4, 167, 132, 240, 76, 164, 18, 45, 20, 48, 85, 206, 121, + ]); + + let ax = multiply_ristretto(&scalar_x, &point_a).unwrap(); + let bx = multiply_ristretto(&scalar_x, &point_b).unwrap(); + + assert_eq!( + add_ristretto(&ax, &bx), + multiply_ristretto(&scalar_x, &add_ristretto(&point_a, &point_b).unwrap()), + ); + } + + #[test] + fn test_multiscalar_multiplication_ristretto() { + let scalar = PodScalar([ + 123, 108, 109, 66, 154, 185, 88, 122, 178, 43, 17, 154, 201, 223, 31, 238, 59, 215, 71, + 154, 215, 143, 177, 158, 9, 136, 32, 223, 139, 13, 133, 5, + ]); + let point = PodRistrettoPoint([ + 158, 2, 130, 90, 148, 36, 172, 155, 86, 196, 74, 139, 30, 98, 44, 225, 155, 207, 135, + 111, 238, 167, 235, 67, 234, 125, 0, 227, 146, 31, 24, 113, + ]); + + let basic_product = multiply_ristretto(&scalar, &point).unwrap(); + let msm_product = multiscalar_multiply_ristretto(&[scalar], &[point]).unwrap(); + + assert_eq!(basic_product, msm_product); + + let scalar_a = PodScalar([ + 8, 161, 219, 155, 192, 137, 153, 26, 27, 40, 30, 17, 124, 194, 26, 41, 32, 7, 161, 45, + 212, 198, 212, 81, 133, 185, 164, 85, 95, 232, 106, 10, + ]); + let scalar_b = PodScalar([ + 135, 207, 106, 208, 107, 127, 46, 82, 66, 22, 136, 125, 105, 62, 69, 34, 213, 210, 17, + 196, 120, 114, 238, 237, 149, 170, 5, 243, 54, 77, 172, 12, + ]); + let point_x = PodRistrettoPoint([ + 130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240, + 179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112, + ]); + let point_y = PodRistrettoPoint([ + 152, 156, 155, 197, 152, 232, 92, 206, 219, 159, 193, 134, 121, 128, 139, 36, 56, 191, + 51, 143, 72, 204, 87, 76, 110, 124, 101, 96, 238, 158, 42, 108, + ]); + + let ax = multiply_ristretto(&scalar_a, &point_x).unwrap(); + let by = multiply_ristretto(&scalar_b, &point_y).unwrap(); + let basic_product = add_ristretto(&ax, &by).unwrap(); + let msm_product = + multiscalar_multiply_ristretto(&[scalar_a, scalar_b], &[point_x, point_y]).unwrap(); + + assert_eq!(basic_product, msm_product); + } +} diff --git a/curve25519/src/scalar.rs b/curve25519/src/scalar.rs new file mode 100644 index 00000000000000..e154851902a043 --- /dev/null +++ b/curve25519/src/scalar.rs @@ -0,0 +1,24 @@ +pub use bytemuck::{Pod, Zeroable}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)] +#[repr(transparent)] +pub struct PodScalar(pub [u8; 32]); + +#[cfg(not(target_os = "solana"))] +mod target_arch { + use {super::*, crate::curve25519::errors::Curve25519Error, curve25519_dalek::scalar::Scalar}; + + impl From<&Scalar> for PodScalar { + fn from(scalar: &Scalar) -> Self { + Self(scalar.to_bytes()) + } + } + + impl TryFrom<&PodScalar> for Scalar { + type Error = Curve25519Error; + + fn try_from(pod: &PodScalar) -> Result { + Scalar::from_canonical_bytes(pod.0).ok_or(Curve25519Error::PodConversion) + } + } +} From 824345e8d86b91ba0657b9cf897b1550f5df7db4 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 02:33:51 +0400 Subject: [PATCH 02/17] remove obsolete comment --- curve25519/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/curve25519/src/lib.rs b/curve25519/src/lib.rs index 19c4aa1388aa9a..31a6b1131f667e 100644 --- a/curve25519/src/lib.rs +++ b/curve25519/src/lib.rs @@ -1,7 +1,4 @@ //! Syscall operations for curve25519 -//! -//! This module lives inside the zk-token-sdk for now, but should move to a general location since -//! it is independent of zk-tokens. pub mod curve_syscall_traits; pub mod edwards; From 382aadd804f839af341ab3b4cd026ba0d6295255 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 02:42:01 +0400 Subject: [PATCH 03/17] fix Cargo.toml files --- Cargo.toml | 4 ++-- curve25519/Cargo.toml | 2 +- programs/bpf_loader/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 80f340868827f7..bcaa03c23d4da1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ members = [ "connection-cache", "core", "cost-model", + "curve25519", "dos", "download-utils", "entry", @@ -128,7 +129,6 @@ members = [ "wen-restart", "zk-keygen", "zk-sdk", - "curve25519", "zk-token-sdk", ] @@ -341,6 +341,7 @@ solana-config-program = { path = "programs/config", version = "=2.0.0" } solana-connection-cache = { path = "connection-cache", version = "=2.0.0", default-features = false } solana-core = { path = "core", version = "=2.0.0" } solana-cost-model = { path = "cost-model", version = "=2.0.0" } +solana-curve25519 = { path = "curve25519", version = "=0.0.1" } solana-download-utils = { path = "download-utils", version = "=2.0.0" } solana-entry = { path = "entry", version = "=2.0.0" } solana-faucet = { path = "faucet", version = "=2.0.0" } @@ -406,7 +407,6 @@ solana-wen-restart = { path = "wen-restart", version = "=2.0.0" } solana-zk-elgamal-proof-program = { path = "programs/zk-elgamal-proof", version = "=2.0.0" } solana-zk-keygen = { path = "zk-keygen", version = "=2.0.0" } solana-zk-sdk = { path = "zk-sdk", version = "=2.0.0" } -solana-curve25519 = { path = "zk-token-curve25519", version = "=0.0.1" } solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=2.0.0" } solana-zk-token-sdk = { path = "zk-token-sdk", version = "=2.0.0" } solana_rbpf = "=0.8.1" diff --git a/curve25519/Cargo.toml b/curve25519/Cargo.toml index 50ab8bdba86de7..c1f667a4e4f58d 100644 --- a/curve25519/Cargo.toml +++ b/curve25519/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "solana--curve25519" +name = "solana-curve25519" description = "Solana Curve25519 Syscalls" documentation = "https://docs.rs/solana-curve25519" version = "0.0.1" diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index bf1f6315729972..148c0c92333995 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -16,12 +16,12 @@ libsecp256k1 = { workspace = true } log = { workspace = true } scopeguard = { workspace = true } solana-compute-budget = { workspace = true } +solana-curve25519 = { workspace = true } solana-measure = { workspace = true } solana-poseidon = { workspace = true } solana-program-runtime = { workspace = true } solana-sdk = { workspace = true } solana-type-overrides = { workspace = true } -solana-zk-token-sdk = { workspace = true } solana_rbpf = { workspace = true } thiserror = { workspace = true } From 6b43ae43ff87ca854fbf01c02fc54c2b9adf87be Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 02:59:05 +0400 Subject: [PATCH 04/17] fix imports --- Cargo.lock | 23 +- curve25519/src/edwards.rs | 6 +- curve25519/src/errors.rs | 18 + curve25519/src/ristretto.rs | 6 +- curve25519/src/scalar.rs | 16 +- programs/bpf_loader/src/syscalls/mod.rs | 18 +- programs/sbf/rust/curve25519/src/lib.rs | 2 +- zk-token-sdk/Cargo.toml | 1 + .../src/curve25519/curve_syscall_traits.rs | 85 ---- zk-token-sdk/src/curve25519/edwards.rs | 381 ----------------- zk-token-sdk/src/curve25519/errors.rs | 7 - zk-token-sdk/src/curve25519/mod.rs | 11 - zk-token-sdk/src/curve25519/ristretto.rs | 386 ------------------ zk-token-sdk/src/curve25519/scalar.rs | 24 -- zk-token-sdk/src/encryption/elgamal.rs | 2 +- zk-token-sdk/src/errors.rs | 19 +- zk-token-sdk/src/lib.rs | 3 +- zk-token-sdk/src/zk_token_elgamal/convert.rs | 20 +- zk-token-sdk/src/zk_token_elgamal/ops.rs | 6 +- .../src/zk_token_elgamal/pod/elgamal.rs | 6 +- .../zk_token_elgamal/pod/grouped_elgamal.rs | 6 +- .../src/zk_token_elgamal/pod/instruction.rs | 5 +- .../src/zk_token_elgamal/pod/pedersen.rs | 3 +- 23 files changed, 81 insertions(+), 973 deletions(-) delete mode 100644 zk-token-sdk/src/curve25519/curve_syscall_traits.rs delete mode 100644 zk-token-sdk/src/curve25519/edwards.rs delete mode 100644 zk-token-sdk/src/curve25519/errors.rs delete mode 100644 zk-token-sdk/src/curve25519/mod.rs delete mode 100644 zk-token-sdk/src/curve25519/ristretto.rs delete mode 100644 zk-token-sdk/src/curve25519/scalar.rs diff --git a/Cargo.lock b/Cargo.lock index e7b66aec56fb28..af74376d49b3c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5529,16 +5529,6 @@ dependencies = [ "sha-1 0.9.8", ] -[[package]] -name = "solana--curve25519" -version = "0.0.1" -dependencies = [ - "bytemuck", - "curve25519-dalek", - "solana-program", - "thiserror", -] - [[package]] name = "solana-account-decoder" version = "2.0.0" @@ -5851,13 +5841,13 @@ dependencies = [ "rand 0.8.5", "scopeguard", "solana-compute-budget", + "solana-curve25519", "solana-measure", "solana-poseidon", "solana-program-runtime", "solana-sdk", "solana-type-overrides", "solana-vote", - "solana-zk-token-sdk", "solana_rbpf", "test-case", "thiserror", @@ -6302,6 +6292,16 @@ dependencies = [ "test-case", ] +[[package]] +name = "solana-curve25519" +version = "0.0.1" +dependencies = [ + "bytemuck", + "curve25519-dalek", + "solana-program", + "thiserror", +] + [[package]] name = "solana-dos" version = "2.0.0" @@ -8086,6 +8086,7 @@ dependencies = [ "serde_derive", "serde_json", "sha3 0.9.1", + "solana-curve25519", "solana-program", "solana-sdk", "subtle", diff --git a/curve25519/src/edwards.rs b/curve25519/src/edwards.rs index 0dd019b1910d0a..c77204564bacd1 100644 --- a/curve25519/src/edwards.rs +++ b/curve25519/src/edwards.rs @@ -9,7 +9,7 @@ pub struct PodEdwardsPoint(pub [u8; 32]); mod target_arch { use { super::*, - crate::curve25519::{ + crate::{ curve_syscall_traits::{GroupOperations, MultiScalarMultiplication, PointValidation}, errors::Curve25519Error, scalar::PodScalar, @@ -134,7 +134,7 @@ mod target_arch { mod target_arch { use { super::*, - crate::curve25519::{ + crate::{ curve_syscall_traits::{ADD, CURVE25519_EDWARDS, MUL, SUB}, scalar::PodScalar, }, @@ -245,7 +245,7 @@ mod target_arch { mod tests { use { super::*, - crate::curve25519::scalar::PodScalar, + crate::scalar::PodScalar, curve25519_dalek::{ constants::ED25519_BASEPOINT_POINT as G, edwards::EdwardsPoint, traits::Identity, }, diff --git a/curve25519/src/errors.rs b/curve25519/src/errors.rs index 2aabc732a39006..2b43a12145ab42 100644 --- a/curve25519/src/errors.rs +++ b/curve25519/src/errors.rs @@ -5,3 +5,21 @@ pub enum Curve25519Error { #[error("pod conversion failed")] PodConversion, } + +#[derive(Error, Clone, Debug, Eq, PartialEq)] +pub enum ElGamalError { + #[error("key derivation method not supported")] + DerivationMethodNotSupported, + #[error("seed length too short for derivation")] + SeedLengthTooShort, + #[error("seed length too long for derivation")] + SeedLengthTooLong, + #[error("failed to deserialize ciphertext")] + CiphertextDeserialization, + #[error("failed to deserialize public key")] + PubkeyDeserialization, + #[error("failed to deserialize keypair")] + KeypairDeserialization, + #[error("failed to deserialize secret key")] + SecretKeyDeserialization, +} diff --git a/curve25519/src/ristretto.rs b/curve25519/src/ristretto.rs index 772441a32aa65f..f2af775fc481a1 100644 --- a/curve25519/src/ristretto.rs +++ b/curve25519/src/ristretto.rs @@ -9,7 +9,7 @@ pub struct PodRistrettoPoint(pub [u8; 32]); mod target_arch { use { super::*, - crate::curve25519::{ + crate::{ curve_syscall_traits::{GroupOperations, MultiScalarMultiplication, PointValidation}, errors::Curve25519Error, scalar::PodScalar, @@ -135,7 +135,7 @@ mod target_arch { mod target_arch { use { super::*, - crate::curve25519::{ + crate::{ curve_syscall_traits::{ADD, CURVE25519_RISTRETTO, MUL, SUB}, scalar::PodScalar, }, @@ -247,7 +247,7 @@ mod target_arch { mod tests { use { super::*, - crate::curve25519::scalar::PodScalar, + crate::scalar::PodScalar, curve25519_dalek::{ constants::RISTRETTO_BASEPOINT_POINT as G, ristretto::RistrettoPoint, traits::Identity, }, diff --git a/curve25519/src/scalar.rs b/curve25519/src/scalar.rs index e154851902a043..e18c568eaa5897 100644 --- a/curve25519/src/scalar.rs +++ b/curve25519/src/scalar.rs @@ -6,7 +6,7 @@ pub struct PodScalar(pub [u8; 32]); #[cfg(not(target_os = "solana"))] mod target_arch { - use {super::*, crate::curve25519::errors::Curve25519Error, curve25519_dalek::scalar::Scalar}; + use {super::*, crate::errors::{Curve25519Error, ElGamalError}, curve25519_dalek::scalar::Scalar}; impl From<&Scalar> for PodScalar { fn from(scalar: &Scalar) -> Self { @@ -21,4 +21,18 @@ mod target_arch { Scalar::from_canonical_bytes(pod.0).ok_or(Curve25519Error::PodConversion) } } + + impl From for PodScalar { + fn from(scalar: Scalar) -> Self { + Self(scalar.to_bytes()) + } + } + + impl TryFrom for Scalar { + type Error = ElGamalError; + + fn try_from(pod: PodScalar) -> Result { + Scalar::from_canonical_bytes(pod.0).ok_or(ElGamalError::CiphertextDeserialization) + } + } } diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index b0e7fa8ad84b53..9336e50a365055 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -901,7 +901,7 @@ declare_builtin_function!( _arg5: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - use solana_zk_token_sdk::curve25519::{curve_syscall_traits::*, edwards, ristretto}; + use solana_curve25519::{curve_syscall_traits::*, edwards, ristretto}; match curve_id { CURVE25519_EDWARDS => { let cost = invoke_context @@ -967,7 +967,7 @@ declare_builtin_function!( result_point_addr: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - use solana_zk_token_sdk::curve25519::{ + use solana_curve25519::{ curve_syscall_traits::*, edwards, ristretto, scalar, }; match curve_id { @@ -1195,7 +1195,7 @@ declare_builtin_function!( result_point_addr: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - use solana_zk_token_sdk::curve25519::{ + use solana_curve25519::{ curve_syscall_traits::*, edwards, ristretto, scalar, }; @@ -2765,7 +2765,7 @@ mod tests { #[test] fn test_syscall_edwards_curve_point_validation() { - use solana_zk_token_sdk::curve25519::curve_syscall_traits::CURVE25519_EDWARDS; + use solana_curve25519::curve_syscall_traits::CURVE25519_EDWARDS; let config = Config::default(); prepare_mockup!(invoke_context, program_id, bpf_loader::id()); @@ -2838,7 +2838,7 @@ mod tests { #[test] fn test_syscall_ristretto_curve_point_validation() { - use solana_zk_token_sdk::curve25519::curve_syscall_traits::CURVE25519_RISTRETTO; + use solana_curve25519::curve_syscall_traits::CURVE25519_RISTRETTO; let config = Config::default(); prepare_mockup!(invoke_context, program_id, bpf_loader::id()); @@ -2911,7 +2911,7 @@ mod tests { #[test] fn test_syscall_edwards_curve_group_ops() { - use solana_zk_token_sdk::curve25519::curve_syscall_traits::{ + use solana_curve25519::curve_syscall_traits::{ ADD, CURVE25519_EDWARDS, MUL, SUB, }; @@ -3068,7 +3068,7 @@ mod tests { #[test] fn test_syscall_ristretto_curve_group_ops() { - use solana_zk_token_sdk::curve25519::curve_syscall_traits::{ + use solana_curve25519::curve_syscall_traits::{ ADD, CURVE25519_RISTRETTO, MUL, SUB, }; @@ -3227,7 +3227,7 @@ mod tests { #[test] fn test_syscall_multiscalar_multiplication() { - use solana_zk_token_sdk::curve25519::curve_syscall_traits::{ + use solana_curve25519::curve_syscall_traits::{ CURVE25519_EDWARDS, CURVE25519_RISTRETTO, }; @@ -3335,7 +3335,7 @@ mod tests { #[test] fn test_syscall_multiscalar_multiplication_maximum_length_exceeded() { - use solana_zk_token_sdk::curve25519::curve_syscall_traits::{ + use solana_curve25519::curve_syscall_traits::{ CURVE25519_EDWARDS, CURVE25519_RISTRETTO, }; diff --git a/programs/sbf/rust/curve25519/src/lib.rs b/programs/sbf/rust/curve25519/src/lib.rs index a8096d65b34710..34f5db287df716 100644 --- a/programs/sbf/rust/curve25519/src/lib.rs +++ b/programs/sbf/rust/curve25519/src/lib.rs @@ -3,7 +3,7 @@ extern crate solana_program; use { solana_program::{custom_heap_default, custom_panic_default, msg}, - solana_zk_token_sdk::curve25519::{edwards, ristretto, scalar}, + solana_curve25519::{edwards, ristretto, scalar}, }; #[no_mangle] diff --git a/zk-token-sdk/Cargo.toml b/zk-token-sdk/Cargo.toml index fb3dc25649b5a8..73b72b09711d48 100644 --- a/zk-token-sdk/Cargo.toml +++ b/zk-token-sdk/Cargo.toml @@ -34,6 +34,7 @@ serde = { workspace = true } serde_derive = { workspace = true } serde_json = { workspace = true } sha3 = "0.9" +solana-curve25519 = { workspace = true } solana-sdk = { workspace = true } subtle = { workspace = true } zeroize = { workspace = true, features = ["zeroize_derive"] } diff --git a/zk-token-sdk/src/curve25519/curve_syscall_traits.rs b/zk-token-sdk/src/curve25519/curve_syscall_traits.rs deleted file mode 100644 index 547f6c948d7cf0..00000000000000 --- a/zk-token-sdk/src/curve25519/curve_syscall_traits.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! The traits representing the basic elliptic curve operations. -//! -//! These traits are instantiatable by all the commonly used elliptic curves and should help in -//! organizing syscall support for other curves in the future. more complicated or curve-specific -//! functions that are needed in cryptographic applications should be representable by combining -//! the associated functions of these traits. -//! -//! NOTE: This module temporarily lives in zk_token_sdk/curve25519, but it is independent of -//! zk-token-sdk or curve25519. It should be moved to a more general location in the future. -//! - -// Functions are organized by the curve traits, which can be instantiated by multiple curve -// representations. The functions take in a `curve_id` (e.g. `CURVE25519_EDWARDS`) and should run -// the associated functions in the appropriate trait instantiation. The `curve_op` function -// additionally takes in an `op_id` (e.g. `ADD`) that controls which associated functions to run in -// `GroupOperations`. - -pub trait PointValidation { - type Point; - - /// Verifies if a byte representation of a curve point lies in the curve. - fn validate_point(&self) -> bool; -} - -pub trait GroupOperations { - type Point; - type Scalar; - - /// Adds two curve points: P_0 + P_1. - fn add(left_point: &Self::Point, right_point: &Self::Point) -> Option; - - /// Subtracts two curve points: P_0 - P_1. - /// - /// NOTE: Altneratively, one can consider replacing this with a `negate` function that maps a - /// curve point P -> -P. Then subtraction can be computed by combining `negate` and `add` - /// syscalls. However, `subtract` is a much more widely used function than `negate`. - fn subtract(left_point: &Self::Point, right_point: &Self::Point) -> Option; - - /// Multiplies a scalar S with a curve point P: S*P - fn multiply(scalar: &Self::Scalar, point: &Self::Point) -> Option; -} - -pub trait MultiScalarMultiplication { - type Scalar; - type Point; - - /// Given a vector of scalsrs S_1, ..., S_N, and curve points P_1, ..., P_N, computes the - /// "inner product": S_1*P_1 + ... + S_N*P_N. - /// - /// NOTE: This operation can be represented by combining `add` and `multiply` functions in - /// `GroupOperations`, but computing it in a single batch is significantly cheaper. Given how - /// commonly used the multiscalar multiplication (MSM) is, it seems to make sense to have a - /// designated trait for MSM support. - /// - /// NOTE: The inputs to the function is a non-fixed size vector and hence, there are some - /// complications in computing the cost for the syscall. The computational costs should only - /// depend on the length of the vectors (and the curve), so it would be ideal to support - /// variable length inputs and compute the syscall cost as is done in eip-197: - /// . If not, then we can - /// consider bounding the length of the input and assigning worst-case cost. - fn multiscalar_multiply( - scalars: &[Self::Scalar], - points: &[Self::Point], - ) -> Option; -} - -pub trait Pairing { - type G1Point; - type G2Point; - type GTPoint; - - /// Applies the bilinear pairing operation to two curve points P1, P2 -> e(P1, P2). This trait - /// is only relevant for "pairing-friendly" curves such as BN254 and BLS12-381. - fn pairing_map( - left_point: &Self::G1Point, - right_point: &Self::G2Point, - ) -> Option; -} - -pub const CURVE25519_EDWARDS: u64 = 0; -pub const CURVE25519_RISTRETTO: u64 = 1; - -pub const ADD: u64 = 0; -pub const SUB: u64 = 1; -pub const MUL: u64 = 2; diff --git a/zk-token-sdk/src/curve25519/edwards.rs b/zk-token-sdk/src/curve25519/edwards.rs deleted file mode 100644 index 0dd019b1910d0a..00000000000000 --- a/zk-token-sdk/src/curve25519/edwards.rs +++ /dev/null @@ -1,381 +0,0 @@ -use bytemuck::{Pod, Zeroable}; -pub use target_arch::*; - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodEdwardsPoint(pub [u8; 32]); - -#[cfg(not(target_os = "solana"))] -mod target_arch { - use { - super::*, - crate::curve25519::{ - curve_syscall_traits::{GroupOperations, MultiScalarMultiplication, PointValidation}, - errors::Curve25519Error, - scalar::PodScalar, - }, - curve25519_dalek::{ - edwards::{CompressedEdwardsY, EdwardsPoint}, - scalar::Scalar, - traits::VartimeMultiscalarMul, - }, - }; - - pub fn validate_edwards(point: &PodEdwardsPoint) -> bool { - point.validate_point() - } - - pub fn add_edwards( - left_point: &PodEdwardsPoint, - right_point: &PodEdwardsPoint, - ) -> Option { - PodEdwardsPoint::add(left_point, right_point) - } - - pub fn subtract_edwards( - left_point: &PodEdwardsPoint, - right_point: &PodEdwardsPoint, - ) -> Option { - PodEdwardsPoint::subtract(left_point, right_point) - } - - pub fn multiply_edwards( - scalar: &PodScalar, - point: &PodEdwardsPoint, - ) -> Option { - PodEdwardsPoint::multiply(scalar, point) - } - - pub fn multiscalar_multiply_edwards( - scalars: &[PodScalar], - points: &[PodEdwardsPoint], - ) -> Option { - PodEdwardsPoint::multiscalar_multiply(scalars, points) - } - - impl From<&EdwardsPoint> for PodEdwardsPoint { - fn from(point: &EdwardsPoint) -> Self { - Self(point.compress().to_bytes()) - } - } - - impl TryFrom<&PodEdwardsPoint> for EdwardsPoint { - type Error = Curve25519Error; - - fn try_from(pod: &PodEdwardsPoint) -> Result { - CompressedEdwardsY::from_slice(&pod.0) - .decompress() - .ok_or(Curve25519Error::PodConversion) - } - } - - impl PointValidation for PodEdwardsPoint { - type Point = Self; - - fn validate_point(&self) -> bool { - CompressedEdwardsY::from_slice(&self.0) - .decompress() - .is_some() - } - } - - impl GroupOperations for PodEdwardsPoint { - type Scalar = PodScalar; - type Point = Self; - - fn add(left_point: &Self, right_point: &Self) -> Option { - let left_point: EdwardsPoint = left_point.try_into().ok()?; - let right_point: EdwardsPoint = right_point.try_into().ok()?; - - let result = &left_point + &right_point; - Some((&result).into()) - } - - fn subtract(left_point: &Self, right_point: &Self) -> Option { - let left_point: EdwardsPoint = left_point.try_into().ok()?; - let right_point: EdwardsPoint = right_point.try_into().ok()?; - - let result = &left_point - &right_point; - Some((&result).into()) - } - - #[cfg(not(target_os = "solana"))] - fn multiply(scalar: &PodScalar, point: &Self) -> Option { - let scalar: Scalar = scalar.try_into().ok()?; - let point: EdwardsPoint = point.try_into().ok()?; - - let result = &scalar * &point; - Some((&result).into()) - } - } - - impl MultiScalarMultiplication for PodEdwardsPoint { - type Scalar = PodScalar; - type Point = Self; - - fn multiscalar_multiply(scalars: &[PodScalar], points: &[Self]) -> Option { - let scalars = scalars - .iter() - .map(|scalar| Scalar::try_from(scalar).ok()) - .collect::>>()?; - - EdwardsPoint::optional_multiscalar_mul( - scalars, - points - .iter() - .map(|point| EdwardsPoint::try_from(point).ok()), - ) - .map(|result| PodEdwardsPoint::from(&result)) - } - } -} - -#[cfg(target_os = "solana")] -mod target_arch { - use { - super::*, - crate::curve25519::{ - curve_syscall_traits::{ADD, CURVE25519_EDWARDS, MUL, SUB}, - scalar::PodScalar, - }, - }; - - pub fn validate_edwards(point: &PodEdwardsPoint) -> bool { - let mut validate_result = 0u8; - let result = unsafe { - solana_program::syscalls::sol_curve_validate_point( - CURVE25519_EDWARDS, - &point.0 as *const u8, - &mut validate_result, - ) - }; - result == 0 - } - - pub fn add_edwards( - left_point: &PodEdwardsPoint, - right_point: &PodEdwardsPoint, - ) -> Option { - let mut result_point = PodEdwardsPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_group_op( - CURVE25519_EDWARDS, - ADD, - &left_point.0 as *const u8, - &right_point.0 as *const u8, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } - - pub fn subtract_edwards( - left_point: &PodEdwardsPoint, - right_point: &PodEdwardsPoint, - ) -> Option { - let mut result_point = PodEdwardsPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_group_op( - CURVE25519_EDWARDS, - SUB, - &left_point.0 as *const u8, - &right_point.0 as *const u8, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } - - pub fn multiply_edwards( - scalar: &PodScalar, - point: &PodEdwardsPoint, - ) -> Option { - let mut result_point = PodEdwardsPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_group_op( - CURVE25519_EDWARDS, - MUL, - &scalar.0 as *const u8, - &point.0 as *const u8, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } - - pub fn multiscalar_multiply_edwards( - scalars: &[PodScalar], - points: &[PodEdwardsPoint], - ) -> Option { - let mut result_point = PodEdwardsPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_multiscalar_mul( - CURVE25519_EDWARDS, - scalars.as_ptr() as *const u8, - points.as_ptr() as *const u8, - points.len() as u64, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::curve25519::scalar::PodScalar, - curve25519_dalek::{ - constants::ED25519_BASEPOINT_POINT as G, edwards::EdwardsPoint, traits::Identity, - }, - }; - - #[test] - fn test_validate_edwards() { - let pod = PodEdwardsPoint(G.compress().to_bytes()); - assert!(validate_edwards(&pod)); - - let invalid_bytes = [ - 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84, - 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79, - ]; - - assert!(!validate_edwards(&PodEdwardsPoint(invalid_bytes))); - } - - #[test] - fn test_edwards_add_subtract() { - // identity - let identity = PodEdwardsPoint(EdwardsPoint::identity().compress().to_bytes()); - let point = PodEdwardsPoint([ - 201, 179, 241, 122, 180, 185, 239, 50, 183, 52, 221, 0, 153, 195, 43, 18, 22, 38, 187, - 206, 179, 192, 210, 58, 53, 45, 150, 98, 89, 17, 158, 11, - ]); - - assert_eq!(add_edwards(&point, &identity).unwrap(), point); - assert_eq!(subtract_edwards(&point, &identity).unwrap(), point); - - // associativity - let point_a = PodEdwardsPoint([ - 33, 124, 71, 170, 117, 69, 151, 247, 59, 12, 95, 125, 133, 166, 64, 5, 2, 27, 90, 27, - 200, 167, 59, 164, 52, 54, 52, 200, 29, 13, 34, 213, - ]); - let point_b = PodEdwardsPoint([ - 70, 222, 137, 221, 253, 204, 71, 51, 78, 8, 124, 1, 67, 200, 102, 225, 122, 228, 111, - 183, 129, 14, 131, 210, 212, 95, 109, 246, 55, 10, 159, 91, - ]); - let point_c = PodEdwardsPoint([ - 72, 60, 66, 143, 59, 197, 111, 36, 181, 137, 25, 97, 157, 201, 247, 215, 123, 83, 220, - 250, 154, 150, 180, 192, 196, 28, 215, 137, 34, 247, 39, 129, - ]); - - assert_eq!( - add_edwards(&add_edwards(&point_a, &point_b).unwrap(), &point_c), - add_edwards(&point_a, &add_edwards(&point_b, &point_c).unwrap()), - ); - - assert_eq!( - subtract_edwards(&subtract_edwards(&point_a, &point_b).unwrap(), &point_c), - subtract_edwards(&point_a, &add_edwards(&point_b, &point_c).unwrap()), - ); - - // commutativity - assert_eq!( - add_edwards(&point_a, &point_b).unwrap(), - add_edwards(&point_b, &point_a).unwrap(), - ); - - // subtraction - let point = PodEdwardsPoint(G.compress().to_bytes()); - let point_negated = PodEdwardsPoint((-G).compress().to_bytes()); - - assert_eq!(point_negated, subtract_edwards(&identity, &point).unwrap(),) - } - - #[test] - fn test_edwards_mul() { - let scalar_a = PodScalar([ - 72, 191, 131, 55, 85, 86, 54, 60, 116, 10, 39, 130, 180, 3, 90, 227, 47, 228, 252, 99, - 151, 71, 118, 29, 34, 102, 117, 114, 120, 50, 57, 8, - ]); - let point_x = PodEdwardsPoint([ - 176, 121, 6, 191, 108, 161, 206, 141, 73, 14, 235, 97, 49, 68, 48, 112, 98, 215, 145, - 208, 44, 188, 70, 10, 180, 124, 230, 15, 98, 165, 104, 85, - ]); - let point_y = PodEdwardsPoint([ - 174, 86, 89, 208, 236, 123, 223, 128, 75, 54, 228, 232, 220, 100, 205, 108, 237, 97, - 105, 79, 74, 192, 67, 224, 185, 23, 157, 116, 216, 151, 223, 81, - ]); - - let ax = multiply_edwards(&scalar_a, &point_x).unwrap(); - let bx = multiply_edwards(&scalar_a, &point_y).unwrap(); - - assert_eq!( - add_edwards(&ax, &bx), - multiply_edwards(&scalar_a, &add_edwards(&point_x, &point_y).unwrap()), - ); - } - - #[test] - fn test_multiscalar_multiplication_edwards() { - let scalar = PodScalar([ - 205, 73, 127, 173, 83, 80, 190, 66, 202, 3, 237, 77, 52, 223, 238, 70, 80, 242, 24, 87, - 111, 84, 49, 63, 194, 76, 202, 108, 62, 240, 83, 15, - ]); - let point = PodEdwardsPoint([ - 222, 174, 184, 139, 143, 122, 253, 96, 0, 207, 120, 157, 112, 38, 54, 189, 91, 144, 78, - 111, 111, 122, 140, 183, 65, 250, 191, 133, 6, 42, 212, 93, - ]); - - let basic_product = multiply_edwards(&scalar, &point).unwrap(); - let msm_product = multiscalar_multiply_edwards(&[scalar], &[point]).unwrap(); - - assert_eq!(basic_product, msm_product); - - let scalar_a = PodScalar([ - 246, 154, 34, 110, 31, 185, 50, 1, 252, 194, 163, 56, 211, 18, 101, 192, 57, 225, 207, - 69, 19, 84, 231, 118, 137, 175, 148, 218, 106, 212, 69, 9, - ]); - let scalar_b = PodScalar([ - 27, 58, 126, 136, 253, 178, 176, 245, 246, 55, 15, 202, 35, 183, 66, 199, 134, 187, - 169, 154, 66, 120, 169, 193, 75, 4, 33, 241, 126, 227, 59, 3, - ]); - let point_x = PodEdwardsPoint([ - 252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168, - 53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133, - ]); - let point_y = PodEdwardsPoint([ - 10, 111, 8, 236, 97, 189, 124, 69, 89, 176, 222, 39, 199, 253, 111, 11, 248, 186, 128, - 90, 120, 128, 248, 210, 232, 183, 93, 104, 111, 150, 7, 241, - ]); - - let ax = multiply_edwards(&scalar_a, &point_x).unwrap(); - let by = multiply_edwards(&scalar_b, &point_y).unwrap(); - let basic_product = add_edwards(&ax, &by).unwrap(); - let msm_product = - multiscalar_multiply_edwards(&[scalar_a, scalar_b], &[point_x, point_y]).unwrap(); - - assert_eq!(basic_product, msm_product); - } -} diff --git a/zk-token-sdk/src/curve25519/errors.rs b/zk-token-sdk/src/curve25519/errors.rs deleted file mode 100644 index 2aabc732a39006..00000000000000 --- a/zk-token-sdk/src/curve25519/errors.rs +++ /dev/null @@ -1,7 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Clone, Debug, Eq, PartialEq)] -pub enum Curve25519Error { - #[error("pod conversion failed")] - PodConversion, -} diff --git a/zk-token-sdk/src/curve25519/mod.rs b/zk-token-sdk/src/curve25519/mod.rs deleted file mode 100644 index 19c4aa1388aa9a..00000000000000 --- a/zk-token-sdk/src/curve25519/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Syscall operations for curve25519 -//! -//! This module lives inside the zk-token-sdk for now, but should move to a general location since -//! it is independent of zk-tokens. - -pub mod curve_syscall_traits; -pub mod edwards; -#[cfg(not(target_os = "solana"))] -pub mod errors; -pub mod ristretto; -pub mod scalar; diff --git a/zk-token-sdk/src/curve25519/ristretto.rs b/zk-token-sdk/src/curve25519/ristretto.rs deleted file mode 100644 index 772441a32aa65f..00000000000000 --- a/zk-token-sdk/src/curve25519/ristretto.rs +++ /dev/null @@ -1,386 +0,0 @@ -use bytemuck::{Pod, Zeroable}; -pub use target_arch::*; - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodRistrettoPoint(pub [u8; 32]); - -#[cfg(not(target_os = "solana"))] -mod target_arch { - use { - super::*, - crate::curve25519::{ - curve_syscall_traits::{GroupOperations, MultiScalarMultiplication, PointValidation}, - errors::Curve25519Error, - scalar::PodScalar, - }, - curve25519_dalek::{ - ristretto::{CompressedRistretto, RistrettoPoint}, - scalar::Scalar, - traits::VartimeMultiscalarMul, - }, - }; - - pub fn validate_ristretto(point: &PodRistrettoPoint) -> bool { - point.validate_point() - } - - pub fn add_ristretto( - left_point: &PodRistrettoPoint, - right_point: &PodRistrettoPoint, - ) -> Option { - PodRistrettoPoint::add(left_point, right_point) - } - - pub fn subtract_ristretto( - left_point: &PodRistrettoPoint, - right_point: &PodRistrettoPoint, - ) -> Option { - PodRistrettoPoint::subtract(left_point, right_point) - } - - pub fn multiply_ristretto( - scalar: &PodScalar, - point: &PodRistrettoPoint, - ) -> Option { - PodRistrettoPoint::multiply(scalar, point) - } - - pub fn multiscalar_multiply_ristretto( - scalars: &[PodScalar], - points: &[PodRistrettoPoint], - ) -> Option { - PodRistrettoPoint::multiscalar_multiply(scalars, points) - } - - impl From<&RistrettoPoint> for PodRistrettoPoint { - fn from(point: &RistrettoPoint) -> Self { - Self(point.compress().to_bytes()) - } - } - - impl TryFrom<&PodRistrettoPoint> for RistrettoPoint { - type Error = Curve25519Error; - - fn try_from(pod: &PodRistrettoPoint) -> Result { - CompressedRistretto::from_slice(&pod.0) - .decompress() - .ok_or(Curve25519Error::PodConversion) - } - } - - impl PointValidation for PodRistrettoPoint { - type Point = Self; - - fn validate_point(&self) -> bool { - CompressedRistretto::from_slice(&self.0) - .decompress() - .is_some() - } - } - - impl GroupOperations for PodRistrettoPoint { - type Scalar = PodScalar; - type Point = Self; - - fn add(left_point: &Self, right_point: &Self) -> Option { - let left_point: RistrettoPoint = left_point.try_into().ok()?; - let right_point: RistrettoPoint = right_point.try_into().ok()?; - - let result = &left_point + &right_point; - Some((&result).into()) - } - - fn subtract(left_point: &Self, right_point: &Self) -> Option { - let left_point: RistrettoPoint = left_point.try_into().ok()?; - let right_point: RistrettoPoint = right_point.try_into().ok()?; - - let result = &left_point - &right_point; - Some((&result).into()) - } - - #[cfg(not(target_os = "solana"))] - fn multiply(scalar: &PodScalar, point: &Self) -> Option { - let scalar: Scalar = scalar.try_into().ok()?; - let point: RistrettoPoint = point.try_into().ok()?; - - let result = &scalar * &point; - Some((&result).into()) - } - } - - impl MultiScalarMultiplication for PodRistrettoPoint { - type Scalar = PodScalar; - type Point = Self; - - fn multiscalar_multiply(scalars: &[PodScalar], points: &[Self]) -> Option { - let scalars = scalars - .iter() - .map(|scalar| Scalar::try_from(scalar).ok()) - .collect::>>()?; - - RistrettoPoint::optional_multiscalar_mul( - scalars, - points - .iter() - .map(|point| RistrettoPoint::try_from(point).ok()), - ) - .map(|result| PodRistrettoPoint::from(&result)) - } - } -} - -#[cfg(target_os = "solana")] -#[allow(unused_variables)] -mod target_arch { - use { - super::*, - crate::curve25519::{ - curve_syscall_traits::{ADD, CURVE25519_RISTRETTO, MUL, SUB}, - scalar::PodScalar, - }, - }; - - pub fn validate_ristretto(point: &PodRistrettoPoint) -> bool { - let mut validate_result = 0u8; - let result = unsafe { - solana_program::syscalls::sol_curve_validate_point( - CURVE25519_RISTRETTO, - &point.0 as *const u8, - &mut validate_result, - ) - }; - - result == 0 - } - - pub fn add_ristretto( - left_point: &PodRistrettoPoint, - right_point: &PodRistrettoPoint, - ) -> Option { - let mut result_point = PodRistrettoPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_group_op( - CURVE25519_RISTRETTO, - ADD, - &left_point.0 as *const u8, - &right_point.0 as *const u8, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } - - pub fn subtract_ristretto( - left_point: &PodRistrettoPoint, - right_point: &PodRistrettoPoint, - ) -> Option { - let mut result_point = PodRistrettoPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_group_op( - CURVE25519_RISTRETTO, - SUB, - &left_point.0 as *const u8, - &right_point.0 as *const u8, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } - - pub fn multiply_ristretto( - scalar: &PodScalar, - point: &PodRistrettoPoint, - ) -> Option { - let mut result_point = PodRistrettoPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_group_op( - CURVE25519_RISTRETTO, - MUL, - &scalar.0 as *const u8, - &point.0 as *const u8, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } - - pub fn multiscalar_multiply_ristretto( - scalars: &[PodScalar], - points: &[PodRistrettoPoint], - ) -> Option { - let mut result_point = PodRistrettoPoint::zeroed(); - let result = unsafe { - solana_program::syscalls::sol_curve_multiscalar_mul( - CURVE25519_RISTRETTO, - scalars.as_ptr() as *const u8, - points.as_ptr() as *const u8, - points.len() as u64, - &mut result_point.0 as *mut u8, - ) - }; - - if result == 0 { - Some(result_point) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::curve25519::scalar::PodScalar, - curve25519_dalek::{ - constants::RISTRETTO_BASEPOINT_POINT as G, ristretto::RistrettoPoint, traits::Identity, - }, - }; - - #[test] - fn test_validate_ristretto() { - let pod = PodRistrettoPoint(G.compress().to_bytes()); - assert!(validate_ristretto(&pod)); - - let invalid_bytes = [ - 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84, - 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79, - ]; - - assert!(!validate_ristretto(&PodRistrettoPoint(invalid_bytes))); - } - - #[test] - fn test_add_subtract_ristretto() { - // identity - let identity = PodRistrettoPoint(RistrettoPoint::identity().compress().to_bytes()); - let point = PodRistrettoPoint([ - 210, 174, 124, 127, 67, 77, 11, 114, 71, 63, 168, 136, 113, 20, 141, 228, 195, 254, - 232, 229, 220, 249, 213, 232, 61, 238, 152, 249, 83, 225, 206, 16, - ]); - - assert_eq!(add_ristretto(&point, &identity).unwrap(), point); - assert_eq!(subtract_ristretto(&point, &identity).unwrap(), point); - - // associativity - let point_a = PodRistrettoPoint([ - 208, 165, 125, 204, 2, 100, 218, 17, 170, 194, 23, 9, 102, 156, 134, 136, 217, 190, 98, - 34, 183, 194, 228, 153, 92, 11, 108, 103, 28, 57, 88, 15, - ]); - let point_b = PodRistrettoPoint([ - 208, 241, 72, 163, 73, 53, 32, 174, 54, 194, 71, 8, 70, 181, 244, 199, 93, 147, 99, - 231, 162, 127, 25, 40, 39, 19, 140, 132, 112, 212, 145, 108, - ]); - let point_c = PodRistrettoPoint([ - 250, 61, 200, 25, 195, 15, 144, 179, 24, 17, 252, 167, 247, 44, 47, 41, 104, 237, 49, - 137, 231, 173, 86, 106, 121, 249, 245, 247, 70, 188, 31, 49, - ]); - - assert_eq!( - add_ristretto(&add_ristretto(&point_a, &point_b).unwrap(), &point_c), - add_ristretto(&point_a, &add_ristretto(&point_b, &point_c).unwrap()), - ); - - assert_eq!( - subtract_ristretto(&subtract_ristretto(&point_a, &point_b).unwrap(), &point_c), - subtract_ristretto(&point_a, &add_ristretto(&point_b, &point_c).unwrap()), - ); - - // commutativity - assert_eq!( - add_ristretto(&point_a, &point_b).unwrap(), - add_ristretto(&point_b, &point_a).unwrap(), - ); - - // subtraction - let point = PodRistrettoPoint(G.compress().to_bytes()); - let point_negated = PodRistrettoPoint((-G).compress().to_bytes()); - - assert_eq!( - point_negated, - subtract_ristretto(&identity, &point).unwrap(), - ) - } - - #[test] - fn test_multiply_ristretto() { - let scalar_x = PodScalar([ - 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250, - 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6, - ]); - let point_a = PodRistrettoPoint([ - 68, 80, 232, 181, 241, 77, 60, 81, 154, 51, 173, 35, 98, 234, 149, 37, 1, 39, 191, 201, - 193, 48, 88, 189, 97, 126, 63, 35, 144, 145, 203, 31, - ]); - let point_b = PodRistrettoPoint([ - 200, 236, 1, 12, 244, 130, 226, 214, 28, 125, 43, 163, 222, 234, 81, 213, 201, 156, 31, - 4, 167, 132, 240, 76, 164, 18, 45, 20, 48, 85, 206, 121, - ]); - - let ax = multiply_ristretto(&scalar_x, &point_a).unwrap(); - let bx = multiply_ristretto(&scalar_x, &point_b).unwrap(); - - assert_eq!( - add_ristretto(&ax, &bx), - multiply_ristretto(&scalar_x, &add_ristretto(&point_a, &point_b).unwrap()), - ); - } - - #[test] - fn test_multiscalar_multiplication_ristretto() { - let scalar = PodScalar([ - 123, 108, 109, 66, 154, 185, 88, 122, 178, 43, 17, 154, 201, 223, 31, 238, 59, 215, 71, - 154, 215, 143, 177, 158, 9, 136, 32, 223, 139, 13, 133, 5, - ]); - let point = PodRistrettoPoint([ - 158, 2, 130, 90, 148, 36, 172, 155, 86, 196, 74, 139, 30, 98, 44, 225, 155, 207, 135, - 111, 238, 167, 235, 67, 234, 125, 0, 227, 146, 31, 24, 113, - ]); - - let basic_product = multiply_ristretto(&scalar, &point).unwrap(); - let msm_product = multiscalar_multiply_ristretto(&[scalar], &[point]).unwrap(); - - assert_eq!(basic_product, msm_product); - - let scalar_a = PodScalar([ - 8, 161, 219, 155, 192, 137, 153, 26, 27, 40, 30, 17, 124, 194, 26, 41, 32, 7, 161, 45, - 212, 198, 212, 81, 133, 185, 164, 85, 95, 232, 106, 10, - ]); - let scalar_b = PodScalar([ - 135, 207, 106, 208, 107, 127, 46, 82, 66, 22, 136, 125, 105, 62, 69, 34, 213, 210, 17, - 196, 120, 114, 238, 237, 149, 170, 5, 243, 54, 77, 172, 12, - ]); - let point_x = PodRistrettoPoint([ - 130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240, - 179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112, - ]); - let point_y = PodRistrettoPoint([ - 152, 156, 155, 197, 152, 232, 92, 206, 219, 159, 193, 134, 121, 128, 139, 36, 56, 191, - 51, 143, 72, 204, 87, 76, 110, 124, 101, 96, 238, 158, 42, 108, - ]); - - let ax = multiply_ristretto(&scalar_a, &point_x).unwrap(); - let by = multiply_ristretto(&scalar_b, &point_y).unwrap(); - let basic_product = add_ristretto(&ax, &by).unwrap(); - let msm_product = - multiscalar_multiply_ristretto(&[scalar_a, scalar_b], &[point_x, point_y]).unwrap(); - - assert_eq!(basic_product, msm_product); - } -} diff --git a/zk-token-sdk/src/curve25519/scalar.rs b/zk-token-sdk/src/curve25519/scalar.rs deleted file mode 100644 index e154851902a043..00000000000000 --- a/zk-token-sdk/src/curve25519/scalar.rs +++ /dev/null @@ -1,24 +0,0 @@ -pub use bytemuck::{Pod, Zeroable}; - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)] -#[repr(transparent)] -pub struct PodScalar(pub [u8; 32]); - -#[cfg(not(target_os = "solana"))] -mod target_arch { - use {super::*, crate::curve25519::errors::Curve25519Error, curve25519_dalek::scalar::Scalar}; - - impl From<&Scalar> for PodScalar { - fn from(scalar: &Scalar) -> Self { - Self(scalar.to_bytes()) - } - } - - impl TryFrom<&PodScalar> for Scalar { - type Error = Curve25519Error; - - fn try_from(pod: &PodScalar) -> Result { - Scalar::from_canonical_bytes(pod.0).ok_or(Curve25519Error::PodConversion) - } - } -} diff --git a/zk-token-sdk/src/encryption/elgamal.rs b/zk-token-sdk/src/encryption/elgamal.rs index 7f0a48820a6f35..567ea2945d0051 100644 --- a/zk-token-sdk/src/encryption/elgamal.rs +++ b/zk-token-sdk/src/encryption/elgamal.rs @@ -21,7 +21,6 @@ use { Pedersen, PedersenCommitment, PedersenOpening, G, H, PEDERSEN_COMMITMENT_LEN, }, }, - errors::ElGamalError, RISTRETTO_POINT_LEN, SCALAR_LEN, }, base64::{prelude::BASE64_STANDARD, Engine}, @@ -40,6 +39,7 @@ use { SeedDerivable, Signer, SignerError, }, }, + solana_curve25519::errors::ElGamalError, std::convert::TryInto, subtle::{Choice, ConstantTimeEq}, zeroize::Zeroize, diff --git a/zk-token-sdk/src/errors.rs b/zk-token-sdk/src/errors.rs index 2d3adb74635574..98a36c585ba045 100644 --- a/zk-token-sdk/src/errors.rs +++ b/zk-token-sdk/src/errors.rs @@ -3,6 +3,7 @@ use crate::range_proof::errors::RangeProofGenerationError; use { crate::{range_proof::errors::RangeProofVerificationError, sigma_proofs::errors::*}, + solana_curve25519::errors::ElGamalError, thiserror::Error, }; @@ -18,24 +19,6 @@ pub enum AuthenticatedEncryptionError { Deserialization, } -#[derive(Error, Clone, Debug, Eq, PartialEq)] -pub enum ElGamalError { - #[error("key derivation method not supported")] - DerivationMethodNotSupported, - #[error("seed length too short for derivation")] - SeedLengthTooShort, - #[error("seed length too long for derivation")] - SeedLengthTooLong, - #[error("failed to deserialize ciphertext")] - CiphertextDeserialization, - #[error("failed to deserialize public key")] - PubkeyDeserialization, - #[error("failed to deserialize keypair")] - KeypairDeserialization, - #[error("failed to deserialize secret key")] - SecretKeyDeserialization, -} - #[cfg(not(target_os = "solana"))] #[derive(Error, Clone, Debug, Eq, PartialEq)] pub enum ProofGenerationError { diff --git a/zk-token-sdk/src/lib.rs b/zk-token-sdk/src/lib.rs index 2946e177358adc..83d8b188366e7d 100644 --- a/zk-token-sdk/src/lib.rs +++ b/zk-token-sdk/src/lib.rs @@ -17,6 +17,8 @@ // // `clippy::op_ref` is turned off to prevent clippy from warning that this is not idiomatic code. +pub use solana_curve25519 as curve25519; + #[cfg(not(target_os = "solana"))] #[macro_use] pub(crate) mod macros; @@ -27,7 +29,6 @@ mod sigma_proofs; #[cfg(not(target_os = "solana"))] mod transcript; -pub mod curve25519; pub mod errors; pub mod instruction; pub mod zk_token_elgamal; diff --git a/zk-token-sdk/src/zk_token_elgamal/convert.rs b/zk-token-sdk/src/zk_token_elgamal/convert.rs index a437c817b41e72..cc7c8a04156695 100644 --- a/zk-token-sdk/src/zk_token_elgamal/convert.rs +++ b/zk-token-sdk/src/zk_token_elgamal/convert.rs @@ -1,4 +1,4 @@ -use {super::pod, crate::curve25519::ristretto::PodRistrettoPoint}; +use {super::pod, solana_curve25519::ristretto::PodRistrettoPoint}; impl From<(pod::PedersenCommitment, pod::DecryptHandle)> for pod::ElGamalCiphertext { fn from((commitment, handle): (pod::PedersenCommitment, pod::DecryptHandle)) -> Self { @@ -49,25 +49,9 @@ impl From for pod::DecryptHandle { mod target_arch { use { super::pod, - crate::{curve25519::scalar::PodScalar, errors::ElGamalError}, - curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar}, - std::convert::TryFrom, + curve25519_dalek::ristretto::CompressedRistretto, }; - impl From for PodScalar { - fn from(scalar: Scalar) -> Self { - Self(scalar.to_bytes()) - } - } - - impl TryFrom for Scalar { - type Error = ElGamalError; - - fn try_from(pod: PodScalar) -> Result { - Scalar::from_canonical_bytes(pod.0).ok_or(ElGamalError::CiphertextDeserialization) - } - } - impl From for pod::CompressedRistretto { fn from(cr: CompressedRistretto) -> Self { Self(cr.to_bytes()) diff --git a/zk-token-sdk/src/zk_token_elgamal/ops.rs b/zk-token-sdk/src/zk_token_elgamal/ops.rs index 38da19c1c2e7f1..d0cd41cc799e02 100644 --- a/zk-token-sdk/src/zk_token_elgamal/ops.rs +++ b/zk-token-sdk/src/zk_token_elgamal/ops.rs @@ -1,9 +1,9 @@ -use crate::{ - curve25519::{ +use { + crate::zk_token_elgamal::pod, + solana_curve25519::{ ristretto::{add_ristretto, multiply_ristretto, subtract_ristretto, PodRistrettoPoint}, scalar::PodScalar, }, - zk_token_elgamal::pod, }; const SHIFT_BITS: usize = 16; diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/elgamal.rs b/zk-token-sdk/src/zk_token_elgamal/pod/elgamal.rs index 64c3e794b4816b..8a329949a984d5 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/elgamal.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/elgamal.rs @@ -2,11 +2,9 @@ #[cfg(not(target_os = "solana"))] use { - crate::{ - encryption::elgamal::{self as decoded}, - errors::ElGamalError, - }, + crate::encryption::elgamal::{self as decoded}, curve25519_dalek::ristretto::CompressedRistretto, + solana_curve25519::errors::ElGamalError, }; use { crate::{ diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs b/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs index c7e820fcd04508..934459da916cc0 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs @@ -3,14 +3,12 @@ #[cfg(not(target_os = "solana"))] use crate::encryption::grouped_elgamal::GroupedElGamalCiphertext; use { - crate::{ - errors::ElGamalError, - zk_token_elgamal::pod::{ + crate::zk_token_elgamal::pod::{ elgamal::{ElGamalCiphertext, DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN}, pedersen::{PedersenCommitment, PEDERSEN_COMMITMENT_LEN}, Pod, Zeroable, - }, }, + solana_curve25519::errors::ElGamalError, std::fmt, }; diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs b/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs index e29e3a500551ee..367afc670d18de 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs @@ -3,7 +3,10 @@ use crate::zk_token_elgamal::pod::{ Zeroable, }; #[cfg(not(target_os = "solana"))] -use crate::{errors::ElGamalError, instruction::transfer as decoded}; +use { + crate::instruction::transfer as decoded, + solana_curve25519::errors::ElGamalError, +}; #[derive(Clone, Copy, Pod, Zeroable)] #[repr(C)] diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs b/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs index d27f307f43df2c..51a638ea5679a3 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs @@ -2,8 +2,9 @@ #[cfg(not(target_os = "solana"))] use { - crate::{encryption::pedersen as decoded, errors::ElGamalError}, + crate::encryption::pedersen as decoded, curve25519_dalek::ristretto::CompressedRistretto, + solana_curve25519::errors::ElGamalError, }; use { crate::{ From e3768eaf3b6276ed081f5facf2269256bc669a52 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 02:59:30 +0400 Subject: [PATCH 05/17] update lock file --- programs/sbf/Cargo.lock | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 7a3c0934750fa4..505a28b96f8723 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -4793,12 +4793,12 @@ dependencies = [ "log", "scopeguard", "solana-compute-budget", + "solana-curve25519", "solana-measure", "solana-poseidon", "solana-program-runtime", "solana-sdk", "solana-type-overrides", - "solana-zk-token-sdk", "solana_rbpf", "thiserror", ] @@ -5047,6 +5047,16 @@ dependencies = [ "solana-vote-program", ] +[[package]] +name = "solana-curve25519" +version = "0.0.1" +dependencies = [ + "bytemuck", + "curve25519-dalek", + "solana-program", + "thiserror", +] + [[package]] name = "solana-download-utils" version = "2.0.0" @@ -6708,6 +6718,7 @@ dependencies = [ "serde_derive", "serde_json", "sha3 0.9.1", + "solana-curve25519", "solana-program", "solana-sdk", "subtle", From 9efb9314643190810ab68ec985f832d6c90c3bfc Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 03:03:05 +0400 Subject: [PATCH 06/17] remove unused deps from zk-token-sdk --- Cargo.lock | 2 -- programs/sbf/Cargo.lock | 1 - zk-token-sdk/Cargo.toml | 4 ---- 3 files changed, 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af74376d49b3c4..5e7432532dad61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8075,7 +8075,6 @@ dependencies = [ "bytemuck", "byteorder", "curve25519-dalek", - "getrandom 0.1.16", "itertools 0.12.1", "lazy_static", "merlin", @@ -8091,7 +8090,6 @@ dependencies = [ "solana-sdk", "subtle", "thiserror", - "tiny-bip39", "zeroize", ] diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 505a28b96f8723..eff3135f86e2cb 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -6707,7 +6707,6 @@ dependencies = [ "bytemuck", "byteorder 1.5.0", "curve25519-dalek", - "getrandom 0.1.14", "itertools 0.12.1", "lazy_static", "merlin", diff --git a/zk-token-sdk/Cargo.toml b/zk-token-sdk/Cargo.toml index 73b72b09711d48..c8392fa01377c0 100644 --- a/zk-token-sdk/Cargo.toml +++ b/zk-token-sdk/Cargo.toml @@ -17,15 +17,11 @@ num-traits = { workspace = true } solana-program = { workspace = true } thiserror = { workspace = true } -[dev-dependencies] -tiny-bip39 = { workspace = true } - [target.'cfg(not(target_os = "solana"))'.dependencies] aes-gcm-siv = { workspace = true } bincode = { workspace = true } byteorder = { workspace = true } curve25519-dalek = { workspace = true, features = ["serde"] } -getrandom = { version = "0.1", features = ["dummy"] } itertools = { workspace = true } lazy_static = { workspace = true } merlin = { workspace = true } From bcb06d69c4b304dbbff2c00317ed6f4dfe80d696 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 03:03:36 +0400 Subject: [PATCH 07/17] fmt --- curve25519/src/scalar.rs | 6 ++++- programs/bpf_loader/src/syscalls/mod.rs | 24 +++++-------------- zk-token-sdk/src/encryption/elgamal.rs | 2 +- zk-token-sdk/src/zk_token_elgamal/convert.rs | 5 +--- .../zk_token_elgamal/pod/grouped_elgamal.rs | 6 ++--- .../src/zk_token_elgamal/pod/instruction.rs | 5 +--- .../src/zk_token_elgamal/pod/pedersen.rs | 3 +-- 7 files changed, 18 insertions(+), 33 deletions(-) diff --git a/curve25519/src/scalar.rs b/curve25519/src/scalar.rs index e18c568eaa5897..bb0cfcf1c90fcb 100644 --- a/curve25519/src/scalar.rs +++ b/curve25519/src/scalar.rs @@ -6,7 +6,11 @@ pub struct PodScalar(pub [u8; 32]); #[cfg(not(target_os = "solana"))] mod target_arch { - use {super::*, crate::errors::{Curve25519Error, ElGamalError}, curve25519_dalek::scalar::Scalar}; + use { + super::*, + crate::errors::{Curve25519Error, ElGamalError}, + curve25519_dalek::scalar::Scalar, + }; impl From<&Scalar> for PodScalar { fn from(scalar: &Scalar) -> Self { diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 9336e50a365055..304359a67cf895 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -967,9 +967,7 @@ declare_builtin_function!( result_point_addr: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - use solana_curve25519::{ - curve_syscall_traits::*, edwards, ristretto, scalar, - }; + use solana_curve25519::{curve_syscall_traits::*, edwards, ristretto, scalar}; match curve_id { CURVE25519_EDWARDS => match group_op { ADD => { @@ -1195,9 +1193,7 @@ declare_builtin_function!( result_point_addr: u64, memory_mapping: &mut MemoryMapping, ) -> Result { - use solana_curve25519::{ - curve_syscall_traits::*, edwards, ristretto, scalar, - }; + use solana_curve25519::{curve_syscall_traits::*, edwards, ristretto, scalar}; if points_len > 512 { return Err(Box::new(SyscallError::InvalidLength)); @@ -2911,9 +2907,7 @@ mod tests { #[test] fn test_syscall_edwards_curve_group_ops() { - use solana_curve25519::curve_syscall_traits::{ - ADD, CURVE25519_EDWARDS, MUL, SUB, - }; + use solana_curve25519::curve_syscall_traits::{ADD, CURVE25519_EDWARDS, MUL, SUB}; let config = Config::default(); prepare_mockup!(invoke_context, program_id, bpf_loader::id()); @@ -3068,9 +3062,7 @@ mod tests { #[test] fn test_syscall_ristretto_curve_group_ops() { - use solana_curve25519::curve_syscall_traits::{ - ADD, CURVE25519_RISTRETTO, MUL, SUB, - }; + use solana_curve25519::curve_syscall_traits::{ADD, CURVE25519_RISTRETTO, MUL, SUB}; let config = Config::default(); prepare_mockup!(invoke_context, program_id, bpf_loader::id()); @@ -3227,9 +3219,7 @@ mod tests { #[test] fn test_syscall_multiscalar_multiplication() { - use solana_curve25519::curve_syscall_traits::{ - CURVE25519_EDWARDS, CURVE25519_RISTRETTO, - }; + use solana_curve25519::curve_syscall_traits::{CURVE25519_EDWARDS, CURVE25519_RISTRETTO}; let config = Config::default(); prepare_mockup!(invoke_context, program_id, bpf_loader::id()); @@ -3335,9 +3325,7 @@ mod tests { #[test] fn test_syscall_multiscalar_multiplication_maximum_length_exceeded() { - use solana_curve25519::curve_syscall_traits::{ - CURVE25519_EDWARDS, CURVE25519_RISTRETTO, - }; + use solana_curve25519::curve_syscall_traits::{CURVE25519_EDWARDS, CURVE25519_RISTRETTO}; let config = Config::default(); prepare_mockup!(invoke_context, program_id, bpf_loader::id()); diff --git a/zk-token-sdk/src/encryption/elgamal.rs b/zk-token-sdk/src/encryption/elgamal.rs index 567ea2945d0051..696bedd369153d 100644 --- a/zk-token-sdk/src/encryption/elgamal.rs +++ b/zk-token-sdk/src/encryption/elgamal.rs @@ -31,6 +31,7 @@ use { traits::Identity, }, serde::{Deserialize, Serialize}, + solana_curve25519::errors::ElGamalError, solana_sdk::{ derivation_path::DerivationPath, signature::Signature, @@ -39,7 +40,6 @@ use { SeedDerivable, Signer, SignerError, }, }, - solana_curve25519::errors::ElGamalError, std::convert::TryInto, subtle::{Choice, ConstantTimeEq}, zeroize::Zeroize, diff --git a/zk-token-sdk/src/zk_token_elgamal/convert.rs b/zk-token-sdk/src/zk_token_elgamal/convert.rs index cc7c8a04156695..286383cc1cd98b 100644 --- a/zk-token-sdk/src/zk_token_elgamal/convert.rs +++ b/zk-token-sdk/src/zk_token_elgamal/convert.rs @@ -47,10 +47,7 @@ impl From for pod::DecryptHandle { #[cfg(not(target_os = "solana"))] mod target_arch { - use { - super::pod, - curve25519_dalek::ristretto::CompressedRistretto, - }; + use {super::pod, curve25519_dalek::ristretto::CompressedRistretto}; impl From for pod::CompressedRistretto { fn from(cr: CompressedRistretto) -> Self { diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs b/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs index 934459da916cc0..8f7e6540acd543 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/grouped_elgamal.rs @@ -4,9 +4,9 @@ use crate::encryption::grouped_elgamal::GroupedElGamalCiphertext; use { crate::zk_token_elgamal::pod::{ - elgamal::{ElGamalCiphertext, DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN}, - pedersen::{PedersenCommitment, PEDERSEN_COMMITMENT_LEN}, - Pod, Zeroable, + elgamal::{ElGamalCiphertext, DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN}, + pedersen::{PedersenCommitment, PEDERSEN_COMMITMENT_LEN}, + Pod, Zeroable, }, solana_curve25519::errors::ElGamalError, std::fmt, diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs b/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs index 367afc670d18de..6a763633b3eb13 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs @@ -3,10 +3,7 @@ use crate::zk_token_elgamal::pod::{ Zeroable, }; #[cfg(not(target_os = "solana"))] -use { - crate::instruction::transfer as decoded, - solana_curve25519::errors::ElGamalError, -}; +use {crate::instruction::transfer as decoded, solana_curve25519::errors::ElGamalError}; #[derive(Clone, Copy, Pod, Zeroable)] #[repr(C)] diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs b/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs index 51a638ea5679a3..831bb7ce75ea95 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/pedersen.rs @@ -2,8 +2,7 @@ #[cfg(not(target_os = "solana"))] use { - crate::encryption::pedersen as decoded, - curve25519_dalek::ristretto::CompressedRistretto, + crate::encryption::pedersen as decoded, curve25519_dalek::ristretto::CompressedRistretto, solana_curve25519::errors::ElGamalError, }; use { From 4d5c427df550b33c76efb46075c245c9f96f05e8 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 03:21:31 +0400 Subject: [PATCH 08/17] add solana-curve25519 patch --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index bcaa03c23d4da1..199be76403d04e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -492,6 +492,7 @@ crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d # # There is a similar override in `programs/sbf/Cargo.toml`. Please keep both # comments and the overrides in sync. +solana-curve25519 = { path = "curve25519" } solana-program = { path = "sdk/program" } solana-zk-sdk = { path = "zk-sdk" } solana-zk-token-sdk = { path = "zk-token-sdk" } From a6b93885594d28bfc108cd97c90223cd025a87d2 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 03:28:35 +0400 Subject: [PATCH 09/17] add missing override to programs/sbf/Cargo.toml --- programs/sbf/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index defd20f4716402..fcf19a565f7bd5 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -218,5 +218,6 @@ members = [ # # There is a similar override in `../../Cargo.toml`. Please keep both comments # and the overrides in sync. +solana-curve25519 = { path = "../../curve25519" } solana-program = { path = "../../sdk/program" } solana-zk-token-sdk = { path = "../../zk-token-sdk" } From 22e71ed027a27226416979439b952a04abf06674 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Mon, 22 Apr 2024 03:37:51 +0400 Subject: [PATCH 10/17] copy over an allow() --- curve25519/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/curve25519/src/lib.rs b/curve25519/src/lib.rs index 31a6b1131f667e..f87620f0dde606 100644 --- a/curve25519/src/lib.rs +++ b/curve25519/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects, clippy::op_ref)] //! Syscall operations for curve25519 pub mod curve_syscall_traits; From 88dbbe6ca2a5b3968f1868e706d2984341705e6f Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 13 Jun 2024 13:41:03 +0400 Subject: [PATCH 11/17] move new crate to curves dir --- Cargo.toml | 6 +++--- {curve25519 => curves/curve25519}/.gitignore | 0 {curve25519 => curves/curve25519}/Cargo.toml | 0 .../curve25519}/src/curve_syscall_traits.rs | 0 {curve25519 => curves/curve25519}/src/edwards.rs | 0 {curve25519 => curves/curve25519}/src/errors.rs | 0 {curve25519 => curves/curve25519}/src/lib.rs | 0 {curve25519 => curves/curve25519}/src/ristretto.rs | 0 {curve25519 => curves/curve25519}/src/scalar.rs | 0 programs/sbf/Cargo.toml | 2 +- 10 files changed, 4 insertions(+), 4 deletions(-) rename {curve25519 => curves/curve25519}/.gitignore (100%) rename {curve25519 => curves/curve25519}/Cargo.toml (100%) rename {curve25519 => curves/curve25519}/src/curve_syscall_traits.rs (100%) rename {curve25519 => curves/curve25519}/src/edwards.rs (100%) rename {curve25519 => curves/curve25519}/src/errors.rs (100%) rename {curve25519 => curves/curve25519}/src/lib.rs (100%) rename {curve25519 => curves/curve25519}/src/ristretto.rs (100%) rename {curve25519 => curves/curve25519}/src/scalar.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 199be76403d04e..2ed0cba2f2bebd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ members = [ "connection-cache", "core", "cost-model", - "curve25519", + "curves/*", "dos", "download-utils", "entry", @@ -341,7 +341,7 @@ solana-config-program = { path = "programs/config", version = "=2.0.0" } solana-connection-cache = { path = "connection-cache", version = "=2.0.0", default-features = false } solana-core = { path = "core", version = "=2.0.0" } solana-cost-model = { path = "cost-model", version = "=2.0.0" } -solana-curve25519 = { path = "curve25519", version = "=0.0.1" } +solana-curve25519 = { path = "curves/curve25519", version = "=0.0.1" } solana-download-utils = { path = "download-utils", version = "=2.0.0" } solana-entry = { path = "entry", version = "=2.0.0" } solana-faucet = { path = "faucet", version = "=2.0.0" } @@ -492,7 +492,7 @@ crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d # # There is a similar override in `programs/sbf/Cargo.toml`. Please keep both # comments and the overrides in sync. -solana-curve25519 = { path = "curve25519" } +solana-curve25519 = { path = "curves/curve25519" } solana-program = { path = "sdk/program" } solana-zk-sdk = { path = "zk-sdk" } solana-zk-token-sdk = { path = "zk-token-sdk" } diff --git a/curve25519/.gitignore b/curves/curve25519/.gitignore similarity index 100% rename from curve25519/.gitignore rename to curves/curve25519/.gitignore diff --git a/curve25519/Cargo.toml b/curves/curve25519/Cargo.toml similarity index 100% rename from curve25519/Cargo.toml rename to curves/curve25519/Cargo.toml diff --git a/curve25519/src/curve_syscall_traits.rs b/curves/curve25519/src/curve_syscall_traits.rs similarity index 100% rename from curve25519/src/curve_syscall_traits.rs rename to curves/curve25519/src/curve_syscall_traits.rs diff --git a/curve25519/src/edwards.rs b/curves/curve25519/src/edwards.rs similarity index 100% rename from curve25519/src/edwards.rs rename to curves/curve25519/src/edwards.rs diff --git a/curve25519/src/errors.rs b/curves/curve25519/src/errors.rs similarity index 100% rename from curve25519/src/errors.rs rename to curves/curve25519/src/errors.rs diff --git a/curve25519/src/lib.rs b/curves/curve25519/src/lib.rs similarity index 100% rename from curve25519/src/lib.rs rename to curves/curve25519/src/lib.rs diff --git a/curve25519/src/ristretto.rs b/curves/curve25519/src/ristretto.rs similarity index 100% rename from curve25519/src/ristretto.rs rename to curves/curve25519/src/ristretto.rs diff --git a/curve25519/src/scalar.rs b/curves/curve25519/src/scalar.rs similarity index 100% rename from curve25519/src/scalar.rs rename to curves/curve25519/src/scalar.rs diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index fcf19a565f7bd5..f69bb94df2405a 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -218,6 +218,6 @@ members = [ # # There is a similar override in `../../Cargo.toml`. Please keep both comments # and the overrides in sync. -solana-curve25519 = { path = "../../curve25519" } +solana-curve25519 = { path = "../../curves/curve25519" } solana-program = { path = "../../sdk/program" } solana-zk-token-sdk = { path = "../../zk-token-sdk" } From 6d67e4dac8b709bf212f4d114432ad32df460825 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 13 Jun 2024 19:45:13 +0400 Subject: [PATCH 12/17] use workspace version --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- curves/curve25519/Cargo.toml | 2 +- programs/sbf/Cargo.lock | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e7432532dad61..8f6090ae0d6c2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -978,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" dependencies = [ "borsh-derive 0.10.3", - "hashbrown 0.13.2", + "hashbrown 0.12.3", ] [[package]] @@ -6294,7 +6294,7 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "0.0.1" +version = "2.0.0" dependencies = [ "bytemuck", "curve25519-dalek", diff --git a/Cargo.toml b/Cargo.toml index 2ed0cba2f2bebd..eafd6cf328ad6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -341,7 +341,7 @@ solana-config-program = { path = "programs/config", version = "=2.0.0" } solana-connection-cache = { path = "connection-cache", version = "=2.0.0", default-features = false } solana-core = { path = "core", version = "=2.0.0" } solana-cost-model = { path = "cost-model", version = "=2.0.0" } -solana-curve25519 = { path = "curves/curve25519", version = "=0.0.1" } +solana-curve25519 = { path = "curves/curve25519", version = "=2.0.0" } solana-download-utils = { path = "download-utils", version = "=2.0.0" } solana-entry = { path = "entry", version = "=2.0.0" } solana-faucet = { path = "faucet", version = "=2.0.0" } diff --git a/curves/curve25519/Cargo.toml b/curves/curve25519/Cargo.toml index c1f667a4e4f58d..e16d753578afd1 100644 --- a/curves/curve25519/Cargo.toml +++ b/curves/curve25519/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-curve25519" description = "Solana Curve25519 Syscalls" documentation = "https://docs.rs/solana-curve25519" -version = "0.0.1" +version = { workspace = true } authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index eff3135f86e2cb..9d092013b78f07 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -727,7 +727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" dependencies = [ "borsh-derive 0.10.3", - "hashbrown 0.13.2", + "hashbrown 0.12.3", ] [[package]] @@ -5049,7 +5049,7 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "0.0.1" +version = "2.0.0" dependencies = [ "bytemuck", "curve25519-dalek", From 683d14f93813332389cf15b07993e7a16dea88a1 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 13 Jun 2024 21:43:28 +0400 Subject: [PATCH 13/17] add back missing dev dep --- Cargo.lock | 1 + zk-token-sdk/Cargo.toml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8f6090ae0d6c2b..9a51b869c9be1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8090,6 +8090,7 @@ dependencies = [ "solana-sdk", "subtle", "thiserror", + "tiny-bip39", "zeroize", ] diff --git a/zk-token-sdk/Cargo.toml b/zk-token-sdk/Cargo.toml index c8392fa01377c0..b7907f52916d7c 100644 --- a/zk-token-sdk/Cargo.toml +++ b/zk-token-sdk/Cargo.toml @@ -17,6 +17,9 @@ num-traits = { workspace = true } solana-program = { workspace = true } thiserror = { workspace = true } +[dev-dependencies] +tiny-bip39 = { workspace = true } + [target.'cfg(not(target_os = "solana"))'.dependencies] aes-gcm-siv = { workspace = true } bincode = { workspace = true } From 82d59be8735c42192368f18c0642f81f3ce353f8 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 13 Jun 2024 21:57:47 +0400 Subject: [PATCH 14/17] add missing dependencies to programs/sbf --- programs/sbf/Cargo.lock | 1 + programs/sbf/Cargo.toml | 1 + programs/sbf/rust/curve25519/Cargo.toml | 1 + 3 files changed, 3 insertions(+) diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 9d092013b78f07..93dd5eb5f7b6fc 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5867,6 +5867,7 @@ dependencies = [ name = "solana-sbf-rust-curve25519" version = "2.0.0" dependencies = [ + "solana-curve25519", "solana-program", "solana-zk-token-sdk", ] diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index f69bb94df2405a..555940ef40a900 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -31,6 +31,7 @@ solana-accounts-db = { path = "../../accounts-db", version = "=2.0.0" } solana-bpf-loader-program = { path = "../bpf_loader", version = "=2.0.0" } solana-cli-output = { path = "../../cli-output", version = "=2.0.0" } solana-compute-budget = { path = "../../compute-budget", version = "=2.0.0" } +solana-curve25519 = { path = "../../curves/curve25519", version = "=2.0.0" } solana-ledger = { path = "../../ledger", version = "=2.0.0" } solana-logger = { path = "../../logger", version = "=2.0.0" } solana-measure = { path = "../../measure", version = "=2.0.0" } diff --git a/programs/sbf/rust/curve25519/Cargo.toml b/programs/sbf/rust/curve25519/Cargo.toml index c75477788e0dca..ad555810ff203e 100644 --- a/programs/sbf/rust/curve25519/Cargo.toml +++ b/programs/sbf/rust/curve25519/Cargo.toml @@ -9,6 +9,7 @@ license = { workspace = true } edition = { workspace = true } [dependencies] +solana-curve25519 = { workspace = true } solana-program = { workspace = true } solana-zk-token-sdk = { workspace = true } From e20f8b23b6e394e99601100ba4a8b40387c7ba06 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 13 Jun 2024 22:06:09 +0400 Subject: [PATCH 15/17] fmt --- programs/sbf/rust/curve25519/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/sbf/rust/curve25519/src/lib.rs b/programs/sbf/rust/curve25519/src/lib.rs index 34f5db287df716..42718278c2c685 100644 --- a/programs/sbf/rust/curve25519/src/lib.rs +++ b/programs/sbf/rust/curve25519/src/lib.rs @@ -2,8 +2,8 @@ extern crate solana_program; use { - solana_program::{custom_heap_default, custom_panic_default, msg}, solana_curve25519::{edwards, ristretto, scalar}, + solana_program::{custom_heap_default, custom_panic_default, msg}, }; #[no_mangle] From 3062a951d0abdba916d51a8c9d4bd3ac0a852836 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Thu, 13 Jun 2024 22:24:33 +0400 Subject: [PATCH 16/17] move dep to the correct dependency table --- zk-token-sdk/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zk-token-sdk/Cargo.toml b/zk-token-sdk/Cargo.toml index b7907f52916d7c..2cc9b4bcb5d15f 100644 --- a/zk-token-sdk/Cargo.toml +++ b/zk-token-sdk/Cargo.toml @@ -14,6 +14,7 @@ base64 = { workspace = true } bytemuck = { workspace = true, features = ["derive"] } num-derive = { workspace = true } num-traits = { workspace = true } +solana-curve25519 = { workspace = true } solana-program = { workspace = true } thiserror = { workspace = true } @@ -33,7 +34,6 @@ serde = { workspace = true } serde_derive = { workspace = true } serde_json = { workspace = true } sha3 = "0.9" -solana-curve25519 = { workspace = true } solana-sdk = { workspace = true } subtle = { workspace = true } zeroize = { workspace = true, features = ["zeroize_derive"] } From 568e201ee88ad8c97040f768009c9e328ce03386 Mon Sep 17 00:00:00 2001 From: kevinheavey Date: Sat, 15 Jun 2024 02:41:09 +0400 Subject: [PATCH 17/17] remove #[cfg(not(target_os = "solana"))] above errors mod --- curves/curve25519/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/curves/curve25519/src/lib.rs b/curves/curve25519/src/lib.rs index f87620f0dde606..d0ab9d4709da11 100644 --- a/curves/curve25519/src/lib.rs +++ b/curves/curve25519/src/lib.rs @@ -3,7 +3,6 @@ pub mod curve_syscall_traits; pub mod edwards; -#[cfg(not(target_os = "solana"))] pub mod errors; pub mod ristretto; pub mod scalar;