Skip to content

Commit ecad5ad

Browse files
mootz12jayz22sisureshleighmccullochOghma
authored
Add bn254 support and expose poseidon/poseidon2 host functions (#1667)
### What * Add bn254 support (#1615, #1628) - A new module `crypto/bn254.rs` with Bn254 point and field types, and expose related host operations. - Implement `Neg` trait for `G1Affine` (#1630) - Update bn254 typenames and add mapping (#1645), also updated bls12-381 type names for consistency * Add raw Poseidon, Poseidon2 support in `CryptoHazmat`, gated by "hazmat-crypto" feature ### Why Expose new crypto functions for protocol 25 ### Known limitations Only the raw host function exposure for Poseidon/Poseidon2 has been added in this PR. The more elaborate setup for sponge, parameters, hash function wrappers will be done in a separate repo [here](https://github.com/stellar/rs-soroban-poseidon) --------- Co-authored-by: Jay Geng <jay@stellar.org> Co-authored-by: Siddharth Suresh <siddharth@stellar.org> Co-authored-by: Leigh <351529+leighmcculloch@users.noreply.github.com> Co-authored-by: Matteo Lisotto <matteo.lisotto@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Nando Vieira <me@fnando.com>
1 parent a60b7e8 commit ecad5ad

File tree

183 files changed

+3514
-377
lines changed

Some content is hidden

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

183 files changed

+3514
-377
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,29 +30,27 @@ soroban-token-spec = { version = "23.4.0", path = "soroban-token-spec" }
3030
stellar-asset-spec = { version = "23.4.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 = "cf58d535ab05d02802a5e804a95524650f8c62c7"
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 = "cf58d535ab05d02802a5e804a95524650f8c62c7"
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 = "cf58d535ab05d02802a5e804a95524650f8c62c7"
4646

4747
[workspace.dependencies.stellar-strkey]
4848
version = "=0.0.13"
4949

5050
[workspace.dependencies.stellar-xdr]
51-
version = "=23.0.0"
51+
version = "=25.0.0"
5252
default-features = false
5353
features = ["curr"]
54-
#git = "https://github.com/stellar/rs-stellar-xdr"
55-
#rev = "67be5955a15f1d3a4df83fe86e6ae107f687141b"
5654

5755
#[patch.crates-io]
5856
#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
@@ -240,7 +240,7 @@ impl LedgerSnapshot {
240240
impl Default for LedgerSnapshot {
241241
fn default() -> Self {
242242
Self {
243-
protocol_version: 23,
243+
protocol_version: 25,
244244
sequence_number: Default::default(),
245245
timestamp: Default::default(),
246246
network_id: Default::default(),

soroban-sdk-macros/src/derive_spec_fn.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use proc_macro2::TokenStream as TokenStream2;
22
use quote::{format_ident, quote};
33
use stellar_xdr::curr as stellar_xdr;
44
use stellar_xdr::{
5-
ScSpecEntry, ScSpecFunctionInputV0, ScSpecFunctionV0, ScSpecTypeDef, ScSymbol, StringM, VecM,
5+
ScSpecEntry, ScSpecFunctionInputV0, ScSpecFunctionV0, ScSpecTypeDef, ScSymbol, StringM,
66
WriteXdr, SCSYMBOL_LIMIT,
77
};
88
use syn::TypeReference;
@@ -153,17 +153,7 @@ pub fn derive_fn_spec(
153153
));
154154
ScSymbol::default()
155155
}),
156-
inputs: spec_args.try_into().unwrap_or_else(|_| {
157-
const MAX: u32 = 10;
158-
errors.push(Error::new(
159-
inputs.iter().nth(MAX as usize).span(),
160-
format!(
161-
"contract function has too many parameters, max count {} parameters",
162-
MAX,
163-
),
164-
));
165-
VecM::<_, MAX>::default()
166-
}),
156+
inputs: spec_args.try_into().unwrap(),
167157
outputs: spec_result.try_into().unwrap(),
168158
});
169159
let spec_xdr = spec_entry.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap();

soroban-sdk-macros/src/map_type.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ pub const FP2_SERIALIZED_SIZE: u32 = FP_SERIALIZED_SIZE * 2;
1616
pub const G1_SERIALIZED_SIZE: u32 = FP_SERIALIZED_SIZE * 2;
1717
pub const G2_SERIALIZED_SIZE: u32 = FP2_SERIALIZED_SIZE * 2;
1818

19+
// BN254 constants - values must match soroban_sdk::crypto::bn254
20+
pub const BN254_FP_SERIALIZED_SIZE: u32 = 32;
21+
pub const BN254_G1_SERIALIZED_SIZE: u32 = BN254_FP_SERIALIZED_SIZE * 2; // 64
22+
pub const BN254_G2_SERIALIZED_SIZE: u32 = BN254_G1_SERIALIZED_SIZE * 2; // 128
23+
1924
#[allow(clippy::too_many_lines)]
2025
pub fn map_type(t: &Type, allow_ref: bool, allow_hash: bool) -> Result<ScSpecTypeDef, Error> {
2126
match t {
@@ -53,13 +58,13 @@ pub fn map_type(t: &Type, allow_ref: bool, allow_hash: bool) -> Result<ScSpecTyp
5358
"MuxedAddress" => Ok(ScSpecTypeDef::MuxedAddress),
5459
"Timepoint" => Ok(ScSpecTypeDef::Timepoint),
5560
"Duration" => Ok(ScSpecTypeDef::Duration),
56-
// The BLS types defined below are represented in the contract's
61+
// The BLS and BN types defined below are represented in the contract's
5762
// interface by their underlying data types, i.e.
5863
// Fp/Fp2/G1Affine/G2Affine => BytesN<N>, Fr => U256. This approach
5964
// simplifies integration with contract development tooling, as it
60-
// avoids introducing new spec types for these BLS constructs.
65+
// avoids introducing new spec types for these constructs.
6166
//
62-
// While this is functionally sound because the BLS types are
67+
// While this is functionally sound because the types are
6368
// essentially newtypes over their inner representations, it means
6469
// that the specific semantic meaning of `G1Affine`, `G2Affine`, or
6570
// `Fr` is not directly visible in the compiled WASM interface. For
@@ -71,6 +76,9 @@ pub fn map_type(t: &Type, allow_ref: bool, allow_hash: bool) -> Result<ScSpecTyp
7176
// Idiom. For more details, see the tracking issue for supporting
7277
// type aliases:
7378
// https://github.com/stellar/rs-soroban-sdk/issues/1063
79+
80+
// These BLS12-381 unprefixed type names
81+
// will be removed in a future release.
7482
"Fp" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
7583
n: FP_SERIALIZED_SIZE,
7684
})),
@@ -84,6 +92,29 @@ pub fn map_type(t: &Type, allow_ref: bool, allow_hash: bool) -> Result<ScSpecTyp
8492
n: G2_SERIALIZED_SIZE,
8593
})),
8694
"Fr" => Ok(ScSpecTypeDef::U256),
95+
// BLS12-381 prefixed type names
96+
"Bls12381Fp" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
97+
n: FP_SERIALIZED_SIZE,
98+
})),
99+
"Bls12381Fp2" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
100+
n: FP2_SERIALIZED_SIZE,
101+
})),
102+
"Bls12381G1Affine" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
103+
n: G1_SERIALIZED_SIZE,
104+
})),
105+
"Bls12381G2Affine" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
106+
n: G2_SERIALIZED_SIZE,
107+
})),
108+
// BN254 prefixed type names
109+
"Bn254Fp" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
110+
n: BN254_FP_SERIALIZED_SIZE,
111+
})),
112+
"Bn254G1Affine" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
113+
n: BN254_G1_SERIALIZED_SIZE,
114+
})),
115+
"Bn254G2Affine" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
116+
n: BN254_G2_SERIALIZED_SIZE,
117+
})),
87118
s => Ok(ScSpecTypeDef::Udt(ScSpecTypeUdt {
88119
name: s.try_into().map_err(|e| {
89120
Error::new(

soroban-sdk/src/crypto.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
use crate::{
44
env::internal::{self, BytesObject},
55
unwrap::UnwrapInfallible,
6-
Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val,
6+
Bytes, BytesN, ConversionError, Env, IntoVal, Symbol, TryFromVal, TryIntoVal, Val, Vec, U256,
77
};
88

99
pub mod bls12_381;
10+
pub mod bn254;
11+
pub(crate) mod utils;
12+
pub use bn254::Fr as BnScalar;
13+
1014
/// A `BytesN<N>` generated by a cryptographic hash function.
1115
///
1216
/// The `Hash<N>` type contains a `BytesN<N>` and can only be constructed in
@@ -182,6 +186,12 @@ impl Crypto {
182186
pub fn bls12_381(&self) -> bls12_381::Bls12_381 {
183187
bls12_381::Bls12_381::new(self.env())
184188
}
189+
190+
/// Get a [Bn254][bn254::Bn254] for accessing the bn254
191+
/// functions.
192+
pub fn bn254(&self) -> bn254::Bn254 {
193+
bn254::Bn254::new(self.env())
194+
}
185195
}
186196

187197
/// # ⚠️ Hazardous Materials
@@ -254,4 +264,68 @@ impl CryptoHazmat {
254264
)
255265
.unwrap_infallible();
256266
}
267+
268+
/// Performs a Poseidon permutation on the input state vector.
269+
///
270+
/// WARNING: This is a low-level permutation function. Most users should use
271+
/// the higher-level `poseidon_hash` function instead.
272+
pub fn poseidon_permutation(
273+
&self,
274+
input: &Vec<U256>,
275+
field: Symbol,
276+
t: u32,
277+
d: u32,
278+
rounds_f: u32,
279+
rounds_p: u32,
280+
mds: &Vec<Vec<U256>>,
281+
round_constants: &Vec<Vec<U256>>,
282+
) -> Vec<U256> {
283+
let env = self.env();
284+
let result = internal::Env::poseidon_permutation(
285+
env,
286+
input.to_object(),
287+
field.to_symbol_val(),
288+
t.into(),
289+
d.into(),
290+
rounds_f.into(),
291+
rounds_p.into(),
292+
mds.to_object(),
293+
round_constants.to_object(),
294+
)
295+
.unwrap_infallible();
296+
297+
result.try_into_val(env).unwrap_infallible()
298+
}
299+
300+
/// Performs a Poseidon2 permutation on the input state vector.
301+
///
302+
/// WARNING: This is a low-level permutation function. Most users should use
303+
/// the higher-level `poseidon2_hash` function instead.
304+
pub fn poseidon2_permutation(
305+
&self,
306+
input: &Vec<U256>,
307+
field: Symbol,
308+
t: u32,
309+
d: u32,
310+
rounds_f: u32,
311+
rounds_p: u32,
312+
mat_internal_diag_m_1: &Vec<U256>,
313+
round_constants: &Vec<Vec<U256>>,
314+
) -> Vec<U256> {
315+
let env = self.env();
316+
let result = internal::Env::poseidon2_permutation(
317+
env,
318+
input.to_object(),
319+
field.to_symbol_val(),
320+
t.into(),
321+
d.into(),
322+
rounds_f.into(),
323+
rounds_p.into(),
324+
mat_internal_diag_m_1.to_object(),
325+
round_constants.to_object(),
326+
)
327+
.unwrap_infallible();
328+
329+
result.try_into_val(env).unwrap_infallible()
330+
}
257331
}

0 commit comments

Comments
 (0)