Skip to content

Commit 7e886f1

Browse files
committed
Bump xdr and env to pick up bn254 and add module for it
1 parent 0738452 commit 7e886f1

File tree

156 files changed

+1291
-217
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+1291
-217
lines changed

Cargo.lock

Lines changed: 250 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ soroban-token-spec = { version = "23.1.0", path = "soroban-token-spec" }
3030
stellar-asset-spec = { version = "23.1.0", path = "stellar-asset-spec" }
3131

3232
[workspace.dependencies.soroban-env-common]
33-
version = "=23.0.1"
34-
#git = "https://github.com/stellar/rs-soroban-env"
35-
#rev = "bd0c80a1fe171e75f8d745f17975a73927d44ecd"
33+
version = "=25.0.0"
34+
git = "https://github.com/stellar/rs-soroban-env"
35+
rev = "2774c09f8ab57199b03d277f8d74e4c9f5442bd9"
3636

3737
[workspace.dependencies.soroban-env-guest]
38-
version = "=23.0.1"
39-
#git = "https://github.com/stellar/rs-soroban-env"
40-
#rev = "bd0c80a1fe171e75f8d745f17975a73927d44ecd"
38+
version = "=25.0.0"
39+
git = "https://github.com/stellar/rs-soroban-env"
40+
rev = "2774c09f8ab57199b03d277f8d74e4c9f5442bd9"
4141

4242
[workspace.dependencies.soroban-env-host]
43-
version = "=23.0.1"
44-
#git = "https://github.com/stellar/rs-soroban-env"
45-
#rev = "bd0c80a1fe171e75f8d745f17975a73927d44ecd"
43+
version = "=25.0.0"
44+
git = "https://github.com/stellar/rs-soroban-env"
45+
rev = "2774c09f8ab57199b03d277f8d74e4c9f5442bd9"
4646

4747
[workspace.dependencies.stellar-strkey]
4848
version = "=0.0.13"
@@ -51,8 +51,8 @@ version = "=0.0.13"
5151
version = "=23.0.0"
5252
default-features = false
5353
features = ["curr"]
54-
#git = "https://github.com/stellar/rs-stellar-xdr"
55-
#rev = "67be5955a15f1d3a4df83fe86e6ae107f687141b"
54+
git = "https://github.com/stellar/rs-stellar-xdr"
55+
rev = "8505f22833f4054227689c35f9cf253a6836cbac"
5656

5757
#[patch.crates-io]
5858
#soroban-env-common = { path = "../rs-soroban-env/soroban-env-common" }

soroban-ledger-snapshot/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl LedgerSnapshot {
166166
impl Default for LedgerSnapshot {
167167
fn default() -> Self {
168168
Self {
169-
protocol_version: 23,
169+
protocol_version: 25,
170170
sequence_number: Default::default(),
171171
timestamp: Default::default(),
172172
network_id: Default::default(),

soroban-sdk/src/crypto.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
};
88

99
pub mod bls12_381;
10+
pub mod bn254;
1011
/// A `BytesN<N>` generated by a cryptographic hash function.
1112
///
1213
/// The `Hash<N>` type contains a `BytesN<N>` and can only be constructed in
@@ -182,6 +183,12 @@ impl Crypto {
182183
pub fn bls12_381(&self) -> bls12_381::Bls12_381 {
183184
bls12_381::Bls12_381::new(self.env())
184185
}
186+
187+
/// Get a [Bn254][bn254::Bn254] for accessing the bn254
188+
/// functions.
189+
pub fn bn254(&self) -> bn254::Bn254 {
190+
bn254::Bn254::new(self.env())
191+
}
185192
}
186193

187194
/// # ⚠️ Hazardous Materials

soroban-sdk/src/crypto/bn254.rs

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
#[cfg(not(target_family = "wasm"))]
2+
use crate::xdr::ScVal;
3+
use crate::{
4+
env::internal::{self, BytesObject, U256Val},
5+
impl_bytesn_repr,
6+
unwrap::{UnwrapInfallible, UnwrapOptimized},
7+
Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256,
8+
};
9+
use core::{cmp::Ordering, fmt::Debug};
10+
11+
const FP_SERIALIZED_SIZE: usize = 32; // Size in bytes of a serialized Fp element in BN254.
12+
pub const G1_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; // Size in bytes of a serialized G1 element in BN254. Each coordinate (X, Y) is 32 bytes.
13+
pub const G2_SERIALIZED_SIZE: usize = G1_SERIALIZED_SIZE * 2; // Size in bytes of a serialized G1 element in BN254. Each coordinate (X, Y) is 32 bytes.
14+
15+
/// Bn254 provides access to curve and pairing operations on the BN254
16+
/// (also known as alt_bn128) curve.
17+
pub struct Bn254 {
18+
env: Env,
19+
}
20+
21+
// TODO: Add comments
22+
23+
#[derive(Clone)]
24+
#[repr(transparent)]
25+
pub struct G1Affine(BytesN<G1_SERIALIZED_SIZE>);
26+
27+
#[derive(Clone)]
28+
#[repr(transparent)]
29+
pub struct G2Affine(BytesN<G2_SERIALIZED_SIZE>);
30+
31+
#[derive(Clone)]
32+
#[repr(transparent)]
33+
pub struct Fr(U256);
34+
35+
impl_bytesn_repr!(G1Affine, G1_SERIALIZED_SIZE);
36+
impl_bytesn_repr!(G2Affine, G2_SERIALIZED_SIZE);
37+
38+
struct Fp(BytesN<FP_SERIALIZED_SIZE>);
39+
40+
impl G1Affine {
41+
pub fn env(&self) -> &Env {
42+
self.0.env()
43+
}
44+
}
45+
46+
impl G2Affine {
47+
pub fn env(&self) -> &Env {
48+
self.0.env()
49+
}
50+
}
51+
52+
impl Fr {
53+
pub fn env(&self) -> &Env {
54+
self.0.env()
55+
}
56+
57+
pub fn from_u256(value: U256) -> Self {
58+
value.into()
59+
}
60+
61+
pub fn to_u256(&self) -> U256 {
62+
self.0.clone()
63+
}
64+
65+
pub fn as_u256(&self) -> &U256 {
66+
&self.0
67+
}
68+
69+
pub fn from_bytes(bytes: BytesN<32>) -> Self {
70+
U256::from_be_bytes(bytes.env(), bytes.as_ref()).into()
71+
}
72+
73+
pub fn to_bytes(&self) -> BytesN<32> {
74+
self.as_u256().to_be_bytes().try_into().unwrap_optimized()
75+
}
76+
77+
pub fn as_val(&self) -> &Val {
78+
self.0.as_val()
79+
}
80+
81+
pub fn to_val(&self) -> Val {
82+
self.0.to_val()
83+
}
84+
}
85+
86+
impl From<U256> for Fr {
87+
fn from(value: U256) -> Self {
88+
Self(value)
89+
}
90+
}
91+
92+
impl From<&Fr> for U256Val {
93+
fn from(value: &Fr) -> Self {
94+
value.as_u256().into()
95+
}
96+
}
97+
98+
impl TryFromVal<Env, Val> for Fr {
99+
type Error = ConversionError;
100+
101+
fn try_from_val(env: &Env, val: &Val) -> Result<Self, Self::Error> {
102+
let u = U256::try_from_val(env, val)?;
103+
Ok(Fr(u))
104+
}
105+
}
106+
107+
impl TryFromVal<Env, Fr> for Val {
108+
type Error = ConversionError;
109+
110+
fn try_from_val(_env: &Env, fr: &Fr) -> Result<Self, Self::Error> {
111+
Ok(fr.to_val())
112+
}
113+
}
114+
115+
impl TryFromVal<Env, &Fr> for Val {
116+
type Error = ConversionError;
117+
118+
fn try_from_val(_env: &Env, fr: &&Fr) -> Result<Self, Self::Error> {
119+
Ok(fr.to_val())
120+
}
121+
}
122+
123+
#[cfg(not(target_family = "wasm"))]
124+
impl From<&Fr> for ScVal {
125+
fn from(v: &Fr) -> Self {
126+
Self::from(&v.0)
127+
}
128+
}
129+
130+
#[cfg(not(target_family = "wasm"))]
131+
impl From<Fr> for ScVal {
132+
fn from(v: Fr) -> Self {
133+
(&v).into()
134+
}
135+
}
136+
137+
impl Eq for Fr {}
138+
139+
impl PartialEq for Fr {
140+
fn eq(&self, other: &Self) -> bool {
141+
self.as_u256().partial_cmp(other.as_u256()) == Some(core::cmp::Ordering::Equal)
142+
}
143+
}
144+
145+
impl Debug for Fr {
146+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
147+
write!(f, "Fr({:?})", self.as_u256())
148+
}
149+
}
150+
151+
impl Bn254 {
152+
pub(crate) fn new(env: &Env) -> Bn254 {
153+
Bn254 { env: env.clone() }
154+
}
155+
156+
pub fn env(&self) -> &Env {
157+
&self.env
158+
}
159+
160+
/// Adds two points `p0` and `p1` in G1.
161+
pub fn g1_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine {
162+
let env = self.env();
163+
let bin =
164+
internal::Env::bn254_g1_add(env, p0.to_object(), p1.to_object()).unwrap_infallible();
165+
unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
166+
}
167+
168+
/// Multiplies a point `p0` in G1 by a scalar.
169+
pub fn g1_mul(&self, p0: &G1Affine, scalar: &Fr) -> G1Affine {
170+
let env = self.env();
171+
let bin =
172+
internal::Env::bn254_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible();
173+
unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
174+
}
175+
176+
// pairing
177+
178+
/// Performs a multi-pairing check between vectors of points in G1 and G2.
179+
///
180+
/// This function computes the pairing for each pair of points in the
181+
/// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if
182+
/// the product of all pairings is equal to 1 in the target group Fq12.
183+
///
184+
/// # Returns:
185+
/// - `true` if the pairing check holds (i.e., the product of pairings equals 1),
186+
/// otherwise `false`.
187+
///
188+
/// # Panics:
189+
/// - If the lengths of `vp1` and `vp2` are not equal or if they are empty.
190+
pub fn pairing_check(&self, vp1: Vec<G1Affine>, vp2: Vec<G2Affine>) -> bool {
191+
let env = self.env();
192+
internal::Env::bn254_multi_pairing_check(env, vp1.into(), vp2.into())
193+
.unwrap_infallible()
194+
.into()
195+
}
196+
}
197+
198+
#[cfg(test)]
199+
mod test {
200+
use super::*;
201+
202+
#[test]
203+
fn test_g1affine_to_val() {
204+
let env = Env::default();
205+
206+
let g1 = G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64]));
207+
let val: Val = g1.clone().into_val(&env);
208+
let rt: G1Affine = val.into_val(&env);
209+
210+
assert_eq!(g1, rt);
211+
}
212+
213+
#[test]
214+
fn test_ref_g1affine_to_val() {
215+
let env = Env::default();
216+
217+
let g1 = G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64]));
218+
let val: Val = (&g1).into_val(&env);
219+
let rt: G1Affine = val.into_val(&env);
220+
221+
assert_eq!(g1, rt);
222+
}
223+
224+
#[test]
225+
fn test_double_ref_g1affine_to_val() {
226+
let env = Env::default();
227+
228+
let g1 = G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64]));
229+
let val: Val = (&&g1).into_val(&env);
230+
let rt: G1Affine = val.into_val(&env);
231+
232+
assert_eq!(g1, rt);
233+
}
234+
235+
#[test]
236+
fn test_fr_to_val() {
237+
let env = Env::default();
238+
239+
let fr = Fr::from_bytes(BytesN::from_array(&env, &[1; 32]));
240+
let val: Val = fr.clone().into_val(&env);
241+
let rt: Fr = val.into_val(&env);
242+
243+
assert_eq!(fr, rt);
244+
}
245+
246+
#[test]
247+
fn test_ref_fr_to_val() {
248+
let env = Env::default();
249+
250+
let fr = Fr::from_bytes(BytesN::from_array(&env, &[1; 32]));
251+
let val: Val = (&fr).into_val(&env);
252+
let rt: Fr = val.into_val(&env);
253+
254+
assert_eq!(fr, rt);
255+
}
256+
257+
#[test]
258+
fn test_double_ref_fr_to_val() {
259+
let env = Env::default();
260+
261+
let fr = Fr::from_bytes(BytesN::from_array(&env, &[1; 32]));
262+
let val: Val = (&&fr).into_val(&env);
263+
let rt: Fr = val.into_val(&env);
264+
265+
assert_eq!(fr, rt);
266+
}
267+
}

soroban-sdk/src/env.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ impl Env {
514514

515515
let rf = Rc::new(EmptySnapshotSource());
516516
let info = internal::LedgerInfo {
517-
protocol_version: 23,
517+
protocol_version: 25,
518518
sequence_number: 0,
519519
timestamp: 0,
520520
network_id: [0; 32],

soroban-sdk/src/tests/cost_estimate.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,21 @@ fn test_cost_estimate_budget() {
235235
Bls12381FrMul 0 None 0 0 332 0 0 0
236236
Bls12381FrPow 0 Some(0) 0 0 691 74558 0 128
237237
Bls12381FrInv 0 None 0 0 35421 0 0 0
238+
Bn254EncodeFp 0 None 0 0 345 0 0 0
239+
Bn254DecodeFp 0 None 0 0 433 0 0 0
240+
Bn254G1CheckPointOnCurve 0 None 0 0 858 0 0 0
241+
Bn254G2CheckPointOnCurve 0 None 0 0 2642 0 0 0
242+
Bn254G2CheckPointInSubgroup 0 None 0 0 2930793 0 0 0
243+
Bn254G1ProjectiveToAffine 0 None 0 0 63 0 0 0
244+
Bn254G1Add 0 None 0 0 3465 0 0 0
245+
Bn254G1Mul 0 None 0 0 1034667 0 0 0
246+
Bn254Pairing 0 Some(0) 0 0 5263357 391912693 1833 6231032
247+
Bn254FrFromU256 0 None 0 0 1940 0 0 0
238248
===============================================================================================================================================================================
239249
Internal details (diagnostics info, does not affect fees)
240250
Total # times meter was called: 197
241-
Shadow cpu limit: 100000000; used: 31868
242-
Shadow mem limit: 41943040; used: 27092
251+
Shadow cpu limit: 100000000; used: 32431
252+
Shadow mem limit: 41943040; used: 27108
243253
===============================================================================================================================================================================
244254
245255

0 commit comments

Comments
 (0)