Skip to content

Commit

Permalink
analysis panic condition for pairing function; add test for infinity
Browse files Browse the repository at this point in the history
  • Loading branch information
jayz22 committed Sep 16, 2024
1 parent 9ad3cad commit f5e68d4
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 5 deletions.
60 changes: 59 additions & 1 deletion soroban-env-host/observations/22/test__bls12_381__pairing.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,63 @@
" 116 call vec_len(Vec(obj#113))": "cpu:41777386, mem:3304",
" 117 ret vec_len -> Ok(U32(4))": "cpu:41777508",
" 118 ret bls12_381_multi_pairing_check -> Ok(True)": "cpu:76385043, mem:298181",
" 119 end": "cpu:76385043, mem:298181, prngs:-/-, objs:-/57@cba81af, vm:-/-, evt:-, store:-/-, foot:-, stk:-, auth:-/-"
" 119 call bytes_new_from_slice(96)": "cpu:661, mem:0",
" 120 ret bytes_new_from_slice -> Ok(Bytes(obj#115))": "cpu:1646, mem:176, objs:-/58@ac299a82",
" 121 call bytes_new_from_slice(96)": "cpu:2307",
" 122 ret bytes_new_from_slice -> Ok(Bytes(obj#117))": "cpu:3292, mem:352, objs:-/59@113198f9",
" 123 call bytes_new_from_slice(96)": "cpu:3953",
" 124 ret bytes_new_from_slice -> Ok(Bytes(obj#119))": "cpu:4938, mem:528, objs:-/60@37eadd60",
" 125 call vec_new_from_slice(3)": "",
" 126 ret vec_new_from_slice -> Ok(Vec(obj#121))": "cpu:6088, mem:632, objs:-/61@b3526a16",
" 127 call vec_put(Vec(obj#121), U32(1), Bytes(obj#123))": "cpu:8395, mem:808, objs:-/62@e4a76af5",
" 128 ret vec_put -> Ok(Vec(obj#125))": "cpu:9649, mem:912, objs:-/63@5b689763",
" 129 call bytes_new_from_slice(192)": "cpu:10310",
" 130 ret bytes_new_from_slice -> Ok(Bytes(obj#127))": "cpu:11319, mem:1184, objs:-/64@8aa5fc15",
" 131 call bytes_new_from_slice(192)": "cpu:11980",
" 132 ret bytes_new_from_slice -> Ok(Bytes(obj#129))": "cpu:12989, mem:1456, objs:-/65@b4fc63e0",
" 133 call bytes_new_from_slice(192)": "cpu:13650",
" 134 ret bytes_new_from_slice -> Ok(Bytes(obj#131))": "cpu:14659, mem:1728, objs:-/66@5c98ecb1",
" 135 call vec_new_from_slice(3)": "",
" 136 ret vec_new_from_slice -> Ok(Vec(obj#133))": "cpu:15809, mem:1832, objs:-/67@3f3912a7",
" 137 call bls12_381_multi_pairing_check(Vec(obj#125), Vec(obj#133))": "",
" 138 call vec_len(Vec(obj#125))": "cpu:16053",
" 139 ret vec_len -> Ok(U32(3))": "cpu:16175",
" 140 call vec_len(Vec(obj#133))": "cpu:2220131, mem:2136",
" 141 ret vec_len -> Ok(U32(3))": "cpu:2220253",
" 142 ret bls12_381_multi_pairing_check -> Ok(False)": "cpu:30815794, mem:223849",
" 143 call bytes_new_from_slice(96)": "cpu:661, mem:0",
" 144 ret bytes_new_from_slice -> Ok(Bytes(obj#135))": "cpu:1646, mem:176, objs:-/68@47cc533a",
" 145 call bytes_new_from_slice(96)": "cpu:2307",
" 146 ret bytes_new_from_slice -> Ok(Bytes(obj#137))": "cpu:3292, mem:352, objs:-/69@9420de5f",
" 147 call bytes_new_from_slice(96)": "cpu:3953",
" 148 ret bytes_new_from_slice -> Ok(Bytes(obj#139))": "cpu:4938, mem:528, objs:-/70@f09a5b7a",
" 149 call vec_new_from_slice(3)": "",
" 150 ret vec_new_from_slice -> Ok(Vec(obj#141))": "cpu:6088, mem:632, objs:-/71@71e61918",
" 151 call bytes_new_from_slice(192)": "cpu:6749",
" 152 ret bytes_new_from_slice -> Ok(Bytes(obj#143))": "cpu:7758, mem:904, objs:-/72@b2c885b9",
" 153 call bytes_new_from_slice(192)": "cpu:8419",
" 154 ret bytes_new_from_slice -> Ok(Bytes(obj#145))": "cpu:9428, mem:1176, objs:-/73@890ee9f4",
" 155 call bytes_new_from_slice(192)": "cpu:10089",
" 156 ret bytes_new_from_slice -> Ok(Bytes(obj#147))": "cpu:11098, mem:1448, objs:-/74@c894f888",
" 157 call vec_new_from_slice(3)": "",
" 158 ret vec_new_from_slice -> Ok(Vec(obj#149))": "cpu:12248, mem:1552, objs:-/75@6f0bc56a",
" 159 call vec_put(Vec(obj#149), U32(2), Bytes(obj#151))": "cpu:15901, mem:1824, objs:-/76@85e20168",
" 160 ret vec_put -> Ok(Vec(obj#153))": "cpu:17155, mem:1928, objs:-/77@35e77666",
" 161 call bls12_381_multi_pairing_check(Vec(obj#141), Vec(obj#153))": "",
" 162 call vec_len(Vec(obj#141))": "cpu:17399",
" 163 ret vec_len -> Ok(U32(3))": "cpu:17521",
" 164 call vec_len(Vec(obj#153))": "cpu:2221477, mem:2232",
" 165 ret vec_len -> Ok(U32(3))": "cpu:2221599",
" 166 ret bls12_381_multi_pairing_check -> Ok(False)": "cpu:30817140, mem:223945",
" 167 call vec_new_from_slice(5)": "cpu:11535, mem:880, objs:-/82@40297403",
" 168 ret vec_new_from_slice -> Ok(Vec(obj#165))": "cpu:12811, mem:1000, objs:-/83@2d838f8e",
" 169 call vec_new_from_slice(5)": "cpu:31076, mem:2360, objs:-/88@c33dc4c0",
" 170 ret vec_new_from_slice -> Ok(Vec(obj#177))": "cpu:32352, mem:2480, objs:-/89@cb153807",
" 171 call bls12_381_multi_pairing_check(Vec(obj#165), Vec(obj#177))": "",
" 172 call vec_len(Vec(obj#165))": "cpu:32596",
" 173 ret vec_len -> Ok(U32(5))": "cpu:32718",
" 174 call vec_len(Vec(obj#177))": "cpu:3705648, mem:2976",
" 175 ret vec_len -> Ok(U32(5))": "cpu:3705770",
" 176 ret bls12_381_multi_pairing_check -> Ok(True)": "cpu:44325299, mem:371018",
" 177 end": "cpu:44325299, mem:371018, prngs:-/-, objs:-/89@cb153807, vm:-/-, evt:-, store:-/-, foot:-, stk:-, auth:-/-"
}
34 changes: 30 additions & 4 deletions soroban-env-host/src/crypto/bls12_381.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,14 +641,40 @@ impl Host {
);
}
self.charge_budget(ContractCostType::Bls12381Pairing, Some(vp1.len() as u64))?;
// This is doing exact same as `Bls12_381::pairing(p, q)`, but avoids
// the `unwrap`

// This calls into `Bls12<Config>::multi_miller_loop`, which just calls
// `ark_ec::models::bls12::Bls12Config::multi_miller_loop` with specific
// parameters defined in `ark_bls12_381::curves`.
//
// Panic analysis:
//
// The following potential panic conditions could exist:
// 1. if two input vector lengths are not equal. There is a `zip_eq`
// which panics if the length of the two vectors are not equal. This is
// weeded out up front.
//
// 2. `coeffs.next().unwrap()`. This occurs when the algorithm Loops
// over pairs of `(a: G1Affine, b: G2Affine)`, converting them into
// `Vec<(G1Prepared, G2Preared::EllCoeff<Config>)>`, the latter contains
// three elements of Fp2. For each pair, the coeffs.next() can at most
// be called twice, when the bit being looped over in `Config::X` is
// set. So this panic cannot happen.
//
// 3. if any of the G1Affine point is infinity. The ell() function which
// calls p.xy().unwrap(), which is when the point is infinity. This
// condition also cannot happen because when the pairs are generated,
// any pair containing a zero point is filtered.
//
// The above analysis is best effort to weed out panics from the source,
// however the algorithm is quite involved. So we cannot be 100% certain
// every panic condition has been excluded.
let mlo = Bls12_381::multi_miller_loop(vp1, vp2);
// final_exponentiation returning None means the `mlo.0.is_zero()`
Bls12_381::final_exponentiation(mlo).ok_or_else(|| {
self.err(
ScErrorType::Crypto,
ScErrorCode::InternalError,
"fail to perform final exponentiation",
ScErrorCode::InvalidInput,
"final_exponentiation has failed, most likely multi_miller_loop produced infinity",
&[],
)
})
Expand Down
39 changes: 39 additions & 0 deletions soroban-env-host/src/test/bls12_381.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,22 @@ fn sample_host_vec<T: UniformRand + CanonicalSerialize>(
host.vec_new_from_slice(&vals)
}

fn zero_g1_vec(host: &Host, vec_len: usize) -> Result<VecObject, HostError> {
let vals: Vec<Val> = (0..vec_len)
.into_iter()
.map(|_| g1_zero(host).unwrap().to_val())
.collect();
host.vec_new_from_slice(&vals)
}

fn zero_g2_vec(host: &Host, vec_len: usize) -> Result<VecObject, HostError> {
let vals: Vec<Val> = (0..vec_len)
.into_iter()
.map(|_| g2_zero(host).unwrap().to_val())
.collect();
host.vec_new_from_slice(&vals)
}

fn sample_fr_vec(host: &Host, vec_len: usize, rng: &mut StdRng) -> Result<VecObject, HostError> {
let vals: Vec<Val> = (0..vec_len)
.into_iter()
Expand Down Expand Up @@ -1514,6 +1530,29 @@ fn pairing() -> Result<(), HostError> {
let res = host.bls12_381_multi_pairing_check(g1_vec, g2_vec)?;
assert!(res.as_val().is_true())
}
// 8. any of g1 point is infinity
{
host.budget_ref().reset_default()?;
let mut vp1 = sample_host_vec::<G1Affine>(&host, G1_SERIALIZED_SIZE, 3, &mut rng)?;
vp1 = host.vec_put(vp1, U32Val::from(1), g1_zero(&host)?.to_val())?;
let vp2 = sample_host_vec::<G2Affine>(&host, G2_SERIALIZED_SIZE, 3, &mut rng)?;
assert!(host.bls12_381_multi_pairing_check(vp1, vp2).is_ok());
}
// 9. any of g2 point is infinity
{
host.budget_ref().reset_default()?;
let vp1 = sample_host_vec::<G1Affine>(&host, G1_SERIALIZED_SIZE, 3, &mut rng)?;
let mut vp2 = sample_host_vec::<G2Affine>(&host, G2_SERIALIZED_SIZE, 3, &mut rng)?;
vp2 = host.vec_put(vp2, U32Val::from(2), g2_zero(&host)?.to_val())?;
assert!(host.bls12_381_multi_pairing_check(vp1, vp2).is_ok());
}
// 10. entire vector is zero
{
host.budget_ref().reset_default()?;
let vp1 = zero_g1_vec(&host, 5)?;
let vp2 = zero_g2_vec(&host, 5)?;
assert!(host.bls12_381_multi_pairing_check(vp1, vp2).is_ok());
}
Ok(())
}

Expand Down

0 comments on commit f5e68d4

Please sign in to comment.