Skip to main content

ark_vrf/suites/
bandersnatch_sw.rs

1//! `ECVRF Bandersnatch-SW SHA-512 Try and Increment` suite.
2//!
3//! Configuration:
4//!
5//! * `SUITE_ID` = b"Bandersnatch-SW-SHA512-TAI-v1" for Short Weierstrass form.
6//!
7//! - The EC group **G** is the prime subgroup of the Bandersnatch elliptic curve,
8//!   in Short Weierstrass form, with finite field and curve parameters as specified in
9//!   [MSZ21](https://eprint.iacr.org/2021/1152).
10//!   For this group, `fLen` = `qLen` = $32$ and `cofactor` = $4$.
11//!
12//! - The prime subgroup generator G is defined as follows:
13//!   - G.x = 30900340493481298850216505686589334086208278925799850409469406976849338430199
14//!   - G.y = 12663882780877899054958035777720958383845500985908634476792678820121468453298
15//!
16//! * `cLen` = 16 (128-bit security level).
17//!
18//! * The key pair generation primitive is `PK = sk * G`, with x the secret
19//!   key scalar and `G` the group generator. In this ciphersuite, the secret
20//!   scalar x is equal to the secret key scalar sk.
21//!
22//! * Nonce generation is inspired by Section 5.4.2.2 of RFC-9381,
23//!   adapted to use the suite's pluggable transcript.
24//!
25//! * The int_to_string function encodes into the 32 bytes little endian
26//!   representation.
27//!
28//! * The string_to_int function decodes from the 32 bytes little endian
29//!   representation.
30//!
31//! * The point_to_string function converts a point in **G** to an octet
32//!   string using compressed form. The y coordinate is encoded using
33//!   int_to_string function and the most significant bit of the last
34//!   octet is used to keep track of the x's sign. This implies that
35//!   the point is encoded on 32 bytes.
36//!
37//! * The string_to_point function tries to decompress the point encoded
38//!   according to `point_to_string` procedure. This function MUST outputs
39//!   "INVALID" if the octet string does not decode to a point on G.
40//!
41//! * The hash function Hash is SHA-512 as specified in
42//!   [RFC6234](https://www.rfc-editor.org/rfc/rfc6234), with hLen = 64.
43//!
44//! * The `ECVRF_encode_to_curve` function uses *Try and Increment*, inspired
45//!   by section 5.4.1.1 of [RFC-9381](https://datatracker.ietf.org/doc/rfc9381),
46//!   adapted to use the suite's pluggable transcript seeded with `SUITE_ID`.
47
48use crate::{pedersen::PedersenSuite, utils::te_sw_map::*, *};
49use ark_ff::MontFp;
50
51#[derive(Debug, Copy, Clone, PartialEq, Eq)]
52pub struct BandersnatchSha512Tai;
53
54type ThisSuite = BandersnatchSha512Tai;
55
56impl Suite for ThisSuite {
57    const SUITE_ID: &'static [u8] = b"Bandersnatch-SW-SHA512-TAI-v1";
58    type Affine = ark_ed_on_bls12_381_bandersnatch::SWAffine;
59    type Transcript = utils::HashTranscript<sha2::Sha512>;
60}
61
62impl PedersenSuite for ThisSuite {
63    const BLINDING_BASE: AffinePoint = {
64        const X: BaseField = MontFp!(
65            "28115362618644671219696075022370511395136332234538034358311199318506963235315"
66        );
67        const Y: BaseField =
68            MontFp!("3900851469868158154936962463930962496000252801946757953905982128670530185313");
69        AffinePoint::new_unchecked(X, Y)
70    };
71}
72
73suite_types!(ThisSuite);
74
75#[cfg(feature = "ring")]
76impl crate::ring::RingSuite for ThisSuite {
77    type Pairing = ark_bls12_381::Bls12_381;
78
79    const ACCUMULATOR_BASE: AffinePoint = {
80        const X: BaseField = MontFp!(
81            "13189182432637108534251278524663360416811744717379968387043749958796254980045"
82        );
83        const Y: BaseField = MontFp!(
84            "14483286006782706188671626508232161325054303360192563232232823772738911894793"
85        );
86        AffinePoint::new_unchecked(X, Y)
87    };
88
89    const PADDING: AffinePoint = {
90        const X: BaseField = MontFp!(
91            "20496180070424734470560955314776462366297546779079302509428101119888111900885"
92        );
93        const Y: BaseField =
94            MontFp!("8839106592405352067483360946162273985142890146060814748321063063028225641813");
95        AffinePoint::new_unchecked(X, Y)
96    };
97}
98
99#[cfg(feature = "ring")]
100ring_suite_types!(ThisSuite);
101
102// sage: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513
103// sage: Fq = GF(q)
104// sage: MONT_A = 29978822694968839326280996386011761570173833766074948509196803838190355340952
105// sage: MONT_B = 25465760566081946422412445027709227188579564747101592991722834452325077642517
106// sage: MONT_A/Fq(3) = 9992940898322946442093665462003920523391277922024982836398934612730118446984
107// sage: Fq(1)/MONT_B = 41180284393978236561320365279764246793818536543197771097409483252169927600582
108impl MapConfig for ark_ed_on_bls12_381_bandersnatch::BandersnatchConfig {
109    const MONT_A_OVER_THREE: ark_ed_on_bls12_381_bandersnatch::Fq =
110        MontFp!("9992940898322946442093665462003920523391277922024982836398934612730118446984");
111    const MONT_B_INV: ark_ed_on_bls12_381_bandersnatch::Fq =
112        MontFp!("41180284393978236561320365279764246793818536543197771097409483252169927600582");
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use crate::{testing, tiny_suite_tests};
119    use ark_ed_on_bls12_381_bandersnatch::{BandersnatchConfig, SWAffine};
120
121    impl crate::testing::SuiteExt for ThisSuite {
122        const SUITE_NAME: &str = "bandersnatch_sw_sha-512_tai";
123    }
124
125    tiny_suite_tests!(ThisSuite);
126    pedersen_suite_tests!(ThisSuite);
127    thin_suite_tests!(ThisSuite);
128
129    #[cfg(feature = "ring")]
130    ring_suite_tests!(ThisSuite);
131
132    #[cfg(feature = "ring")]
133    impl crate::ring::testing::RingSuiteExt for ThisSuite {
134        const SRS_FILE: &str = crate::testing::BLS12_381_PCS_SRS_FILE;
135
136        fn ring_setup() -> &'static RingSetup {
137            use std::sync::OnceLock;
138            static RING_SETUP: OnceLock<RingSetup> = OnceLock::new();
139            RING_SETUP.get_or_init(Self::load_ring_setup)
140        }
141    }
142
143    #[test]
144    fn sw_to_te_roundtrip() {
145        let roundtrip = |org_point| {
146            let te_point = sw_to_te::<BandersnatchConfig>(&org_point).unwrap();
147            assert!(te_point.is_on_curve());
148            let sw_point = te_to_sw::<BandersnatchConfig>(&te_point).unwrap();
149            assert!(sw_point.is_on_curve());
150            assert_eq!(org_point, sw_point);
151        };
152        roundtrip(testing::random_val::<SWAffine>(None));
153        roundtrip(AffinePoint::generator());
154    }
155
156    #[test]
157    fn identity_point_rejected() {
158        use ark_ed_on_bls12_381_bandersnatch::EdwardsAffine;
159
160        // SW identity -> TE must fail
161        let sw_identity = SWAffine::zero();
162        assert!(sw_to_te::<BandersnatchConfig>(&sw_identity).is_none());
163        assert!(<SWAffine as TEMapping<BandersnatchConfig>>::into_te(sw_identity).is_none());
164
165        // TE identity -> SW must fail
166        let te_identity = EdwardsAffine::zero();
167        assert!(te_to_sw::<BandersnatchConfig>(&te_identity).is_none());
168        assert!(<EdwardsAffine as SWMapping<BandersnatchConfig>>::into_sw(te_identity).is_none());
169    }
170
171    #[cfg(feature = "ring")]
172    #[test]
173    fn identity_in_ring_rejected() {
174        use crate::ring::{RingSetup, testing::TEST_RING_SIZE};
175
176        let rng = &mut ark_std::test_rng();
177        let ring_setup = RingSetup::<ThisSuite>::from_rand(TEST_RING_SIZE, rng);
178
179        let mut pks = testing::random_vec::<AffinePoint>(TEST_RING_SIZE, Some(rng));
180        pks[0] = AffinePoint::zero();
181
182        assert!(ring_setup.prover_key(&pks).is_err());
183        assert!(ring_setup.verifier_key(&pks).is_err());
184    }
185}